Merge "OpenJDK 11: Merging in java.nio.channels.Selector and SelectionKey."
diff --git a/api/current.txt b/api/current.txt
index 52291e7..28bd836 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -1577,6 +1577,8 @@
     ctor public FileReader(String) throws java.io.FileNotFoundException;
     ctor public FileReader(java.io.File) throws java.io.FileNotFoundException;
     ctor public FileReader(java.io.FileDescriptor);
+    ctor public FileReader(String, java.nio.charset.Charset) throws java.io.IOException;
+    ctor public FileReader(java.io.File, java.nio.charset.Charset) throws java.io.IOException;
   }
 
   public class FileWriter extends java.io.OutputStreamWriter {
@@ -1585,6 +1587,10 @@
     ctor public FileWriter(java.io.File) throws java.io.IOException;
     ctor public FileWriter(java.io.File, boolean) throws java.io.IOException;
     ctor public FileWriter(java.io.FileDescriptor);
+    ctor public FileWriter(String, java.nio.charset.Charset) throws java.io.IOException;
+    ctor public FileWriter(String, java.nio.charset.Charset, boolean) throws java.io.IOException;
+    ctor public FileWriter(java.io.File, java.nio.charset.Charset) throws java.io.IOException;
+    ctor public FileWriter(java.io.File, java.nio.charset.Charset, boolean) throws java.io.IOException;
   }
 
   @java.lang.FunctionalInterface public interface FilenameFilter {
@@ -1946,10 +1952,13 @@
     ctor public PrintStream(java.io.OutputStream);
     ctor public PrintStream(java.io.OutputStream, boolean);
     ctor public PrintStream(java.io.OutputStream, boolean, String) throws java.io.UnsupportedEncodingException;
+    ctor public PrintStream(java.io.OutputStream, boolean, java.nio.charset.Charset);
     ctor public PrintStream(String) throws java.io.FileNotFoundException;
     ctor public PrintStream(String, String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public PrintStream(String, java.nio.charset.Charset) throws java.io.IOException;
     ctor public PrintStream(java.io.File) throws java.io.FileNotFoundException;
     ctor public PrintStream(java.io.File, String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public PrintStream(java.io.File, java.nio.charset.Charset) throws java.io.IOException;
     method public java.io.PrintStream append(CharSequence);
     method public java.io.PrintStream append(CharSequence, int, int);
     method public java.io.PrintStream append(char);
@@ -1990,10 +1999,13 @@
     ctor public PrintWriter(@NonNull java.io.Writer, boolean);
     ctor public PrintWriter(@NonNull java.io.OutputStream);
     ctor public PrintWriter(@NonNull java.io.OutputStream, boolean);
+    ctor public PrintWriter(@NonNull java.io.OutputStream, boolean, @NonNull java.nio.charset.Charset);
     ctor public PrintWriter(@NonNull String) throws java.io.FileNotFoundException;
     ctor public PrintWriter(@NonNull String, @NonNull String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public PrintWriter(@NonNull String, @NonNull java.nio.charset.Charset) throws java.io.IOException;
     ctor public PrintWriter(@NonNull java.io.File) throws java.io.FileNotFoundException;
     ctor public PrintWriter(@NonNull java.io.File, @NonNull String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public PrintWriter(@NonNull java.io.File, @NonNull java.nio.charset.Charset) throws java.io.IOException;
     method @NonNull public java.io.PrintWriter append(@Nullable CharSequence);
     method @NonNull public java.io.PrintWriter append(@Nullable CharSequence, int, int);
     method @NonNull public java.io.PrintWriter append(char);
@@ -2100,6 +2112,7 @@
     ctor protected Reader(Object);
     method public void mark(int) throws java.io.IOException;
     method public boolean markSupported();
+    method public static java.io.Reader nullReader();
     method public int read(java.nio.CharBuffer) throws java.io.IOException;
     method public int read() throws java.io.IOException;
     method public int read(char[]) throws java.io.IOException;
@@ -2107,6 +2120,7 @@
     method public boolean ready() throws java.io.IOException;
     method public void reset() throws java.io.IOException;
     method public long skip(long) throws java.io.IOException;
+    method public long transferTo(java.io.Writer) throws java.io.IOException;
     field protected Object lock;
   }
 
@@ -2220,6 +2234,7 @@
     method public java.io.Writer append(CharSequence) throws java.io.IOException;
     method public java.io.Writer append(CharSequence, int, int) throws java.io.IOException;
     method public java.io.Writer append(char) throws java.io.IOException;
+    method public static java.io.Writer nullWriter();
     method public void write(int) throws java.io.IOException;
     method public void write(char[]) throws java.io.IOException;
     method public abstract void write(char[], int, int) throws java.io.IOException;
@@ -4806,9 +4821,9 @@
     method public java.math.BigDecimal add(java.math.BigDecimal, java.math.MathContext);
     method public byte byteValueExact();
     method public int compareTo(java.math.BigDecimal);
-    method public java.math.BigDecimal divide(java.math.BigDecimal, int, int);
+    method @Deprecated public java.math.BigDecimal divide(java.math.BigDecimal, int, int);
     method public java.math.BigDecimal divide(java.math.BigDecimal, int, java.math.RoundingMode);
-    method public java.math.BigDecimal divide(java.math.BigDecimal, int);
+    method @Deprecated public java.math.BigDecimal divide(java.math.BigDecimal, int);
     method public java.math.BigDecimal divide(java.math.BigDecimal, java.math.RoundingMode);
     method public java.math.BigDecimal divide(java.math.BigDecimal);
     method public java.math.BigDecimal divide(java.math.BigDecimal, java.math.MathContext);
@@ -4841,10 +4856,11 @@
     method public int scale();
     method public java.math.BigDecimal scaleByPowerOfTen(int);
     method public java.math.BigDecimal setScale(int, java.math.RoundingMode);
-    method public java.math.BigDecimal setScale(int, int);
+    method @Deprecated public java.math.BigDecimal setScale(int, int);
     method public java.math.BigDecimal setScale(int);
     method public short shortValueExact();
     method public int signum();
+    method public java.math.BigDecimal sqrt(java.math.MathContext);
     method public java.math.BigDecimal stripTrailingZeros();
     method public java.math.BigDecimal subtract(java.math.BigDecimal);
     method public java.math.BigDecimal subtract(java.math.BigDecimal, java.math.MathContext);
@@ -4858,20 +4874,22 @@
     method public static java.math.BigDecimal valueOf(long);
     method public static java.math.BigDecimal valueOf(double);
     field public static final java.math.BigDecimal ONE;
-    field public static final int ROUND_CEILING = 2; // 0x2
-    field public static final int ROUND_DOWN = 1; // 0x1
-    field public static final int ROUND_FLOOR = 3; // 0x3
-    field public static final int ROUND_HALF_DOWN = 5; // 0x5
-    field public static final int ROUND_HALF_EVEN = 6; // 0x6
-    field public static final int ROUND_HALF_UP = 4; // 0x4
-    field public static final int ROUND_UNNECESSARY = 7; // 0x7
-    field public static final int ROUND_UP = 0; // 0x0
+    field @Deprecated public static final int ROUND_CEILING = 2; // 0x2
+    field @Deprecated public static final int ROUND_DOWN = 1; // 0x1
+    field @Deprecated public static final int ROUND_FLOOR = 3; // 0x3
+    field @Deprecated public static final int ROUND_HALF_DOWN = 5; // 0x5
+    field @Deprecated public static final int ROUND_HALF_EVEN = 6; // 0x6
+    field @Deprecated public static final int ROUND_HALF_UP = 4; // 0x4
+    field @Deprecated public static final int ROUND_UNNECESSARY = 7; // 0x7
+    field @Deprecated public static final int ROUND_UP = 0; // 0x0
     field public static final java.math.BigDecimal TEN;
     field public static final java.math.BigDecimal ZERO;
   }
 
   public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> {
+    ctor public BigInteger(byte[], int, int);
     ctor public BigInteger(byte[]);
+    ctor public BigInteger(int, byte[], int, int);
     ctor public BigInteger(int, byte[]);
     ctor public BigInteger(@NonNull String, int);
     ctor public BigInteger(@NonNull String);
@@ -4916,6 +4934,8 @@
     method @NonNull public java.math.BigInteger shiftRight(int);
     method public short shortValueExact();
     method public int signum();
+    method @NonNull public java.math.BigInteger sqrt();
+    method @NonNull public java.math.BigInteger[] sqrtAndRemainder();
     method @NonNull public java.math.BigInteger subtract(@NonNull java.math.BigInteger);
     method public boolean testBit(int);
     method public byte[] toByteArray();
@@ -4924,6 +4944,7 @@
     method @NonNull public java.math.BigInteger xor(@NonNull java.math.BigInteger);
     field @NonNull public static final java.math.BigInteger ONE;
     field @NonNull public static final java.math.BigInteger TEN;
+    field @NonNull public static final java.math.BigInteger TWO;
     field @NonNull public static final java.math.BigInteger ZERO;
   }
 
@@ -6739,6 +6760,7 @@
   public abstract class FileStore {
     ctor protected FileStore();
     method public abstract Object getAttribute(String) throws java.io.IOException;
+    method public long getBlockSize() throws java.io.IOException;
     method public abstract <V extends java.nio.file.attribute.FileStoreAttributeView> V getFileStoreAttributeView(Class<V>);
     method public abstract long getTotalSpace() throws java.io.IOException;
     method public abstract long getUnallocatedSpace() throws java.io.IOException;
@@ -8510,6 +8532,12 @@
     method public final java.security.cert.X509Certificate getTrustedCert();
   }
 
+  public final class URICertStoreParameters implements java.security.cert.CertStoreParameters {
+    ctor public URICertStoreParameters(java.net.URI);
+    method public java.security.cert.URICertStoreParameters clone();
+    method public java.net.URI getURI();
+  }
+
   public abstract class X509CRL extends java.security.cert.CRL implements java.security.cert.X509Extension {
     ctor protected X509CRL();
     method public abstract byte[] getEncoded() throws java.security.cert.CRLException;
@@ -12367,6 +12395,34 @@
     method public static int binarySearch(@NonNull Object[], int, int, @NonNull Object);
     method public static <T> int binarySearch(@NonNull T[], T, @Nullable java.util.Comparator<? super T>);
     method public static <T> int binarySearch(@NonNull T[], int, int, T, @Nullable java.util.Comparator<? super T>);
+    method public static int compare(@Nullable boolean[], @Nullable boolean[]);
+    method public static int compare(@NonNull boolean[], int, int, @NonNull boolean[], int, int);
+    method public static int compare(@Nullable byte[], @Nullable byte[]);
+    method public static int compare(@NonNull byte[], int, int, @NonNull byte[], int, int);
+    method public static int compare(@Nullable short[], @Nullable short[]);
+    method public static int compare(@NonNull short[], int, int, @NonNull short[], int, int);
+    method public static int compare(@Nullable char[], @Nullable char[]);
+    method public static int compare(@NonNull char[], int, int, @NonNull char[], int, int);
+    method public static int compare(@Nullable int[], @Nullable int[]);
+    method public static int compare(@NonNull int[], int, int, @NonNull int[], int, int);
+    method public static int compare(@Nullable long[], @Nullable long[]);
+    method public static int compare(@NonNull long[], int, int, @NonNull long[], int, int);
+    method public static int compare(@Nullable float[], @Nullable float[]);
+    method public static int compare(@NonNull float[], int, int, @NonNull float[], int, int);
+    method public static int compare(@Nullable double[], @Nullable double[]);
+    method public static int compare(@NonNull double[], int, int, @NonNull double[], int, int);
+    method public static <T extends java.lang.Comparable<? super T>> int compare(@Nullable T[], @Nullable T[]);
+    method public static <T extends java.lang.Comparable<? super T>> int compare(@NonNull T[], int, int, @NonNull T[], int, int);
+    method public static <T> int compare(@Nullable T[], @Nullable T[], @NonNull java.util.Comparator<? super T>);
+    method public static <T> int compare(@NonNull T[], int, int, @NonNull T[], int, int, @NonNull java.util.Comparator<? super T>);
+    method public static int compareUnsigned(@Nullable byte[], @Nullable byte[]);
+    method public static int compareUnsigned(@NonNull byte[], int, int, @NonNull byte[], int, int);
+    method public static int compareUnsigned(@Nullable short[], @Nullable short[]);
+    method public static int compareUnsigned(@NonNull short[], int, int, @NonNull short[], int, int);
+    method public static int compareUnsigned(@Nullable int[], @Nullable int[]);
+    method public static int compareUnsigned(@NonNull int[], int, int, @NonNull int[], int, int);
+    method public static int compareUnsigned(@Nullable long[], @Nullable long[]);
+    method public static int compareUnsigned(@NonNull long[], int, int, @NonNull long[], int, int);
     method @NonNull public static <T> T[] copyOf(@NonNull T[], int);
     method @NonNull public static <T, U> T[] copyOf(@NonNull U[], int, @NonNull Class<? extends T[]>);
     method @NonNull public static byte[] copyOf(@NonNull byte[], int);
@@ -12391,14 +12447,25 @@
     method public static int deepHashCode(@Nullable Object[]);
     method @NonNull public static String deepToString(@Nullable Object[]);
     method public static boolean equals(@Nullable long[], @Nullable long[]);
+    method public static boolean equals(@NonNull long[], int, int, @NonNull long[], int, int);
     method public static boolean equals(@Nullable int[], @Nullable int[]);
+    method public static boolean equals(@NonNull int[], int, int, @NonNull int[], int, int);
     method public static boolean equals(@Nullable short[], @Nullable short[]);
+    method public static boolean equals(@NonNull short[], int, int, @NonNull short[], int, int);
     method public static boolean equals(@Nullable char[], @Nullable char[]);
+    method public static boolean equals(@NonNull char[], int, int, @NonNull char[], int, int);
     method public static boolean equals(@Nullable byte[], @Nullable byte[]);
+    method public static boolean equals(@NonNull byte[], int, int, @NonNull byte[], int, int);
     method public static boolean equals(@Nullable boolean[], @Nullable boolean[]);
+    method public static boolean equals(@NonNull boolean[], int, int, @NonNull boolean[], int, int);
     method public static boolean equals(@Nullable double[], @Nullable double[]);
+    method public static boolean equals(@NonNull double[], int, int, @NonNull double[], int, int);
     method public static boolean equals(@Nullable float[], @Nullable float[]);
+    method public static boolean equals(@NonNull float[], int, int, @NonNull float[], int, int);
     method public static boolean equals(@Nullable Object[], @Nullable Object[]);
+    method public static boolean equals(@NonNull Object[], int, int, @NonNull Object[], int, int);
+    method public static <T> boolean equals(@Nullable T[], @Nullable T[], @NonNull java.util.Comparator<? super T>);
+    method public static <T> boolean equals(@NonNull T[], int, int, @NonNull T[], int, int, @NonNull java.util.Comparator<? super T>);
     method public static void fill(@NonNull long[], long);
     method public static void fill(@NonNull long[], int, int, long);
     method public static void fill(@NonNull int[], int);
@@ -12426,6 +12493,26 @@
     method public static int hashCode(@Nullable float[]);
     method public static int hashCode(@Nullable double[]);
     method public static int hashCode(@Nullable Object[]);
+    method public static int mismatch(@NonNull boolean[], @NonNull boolean[]);
+    method public static int mismatch(@NonNull boolean[], int, int, @NonNull boolean[], int, int);
+    method public static int mismatch(@NonNull byte[], @NonNull byte[]);
+    method public static int mismatch(byte[], int, int, byte[], int, int);
+    method public static int mismatch(@NonNull char[], @NonNull char[]);
+    method public static int mismatch(@NonNull char[], int, int, @NonNull char[], int, int);
+    method public static int mismatch(@NonNull short[], @NonNull short[]);
+    method public static int mismatch(@NonNull short[], int, int, @NonNull short[], int, int);
+    method public static int mismatch(@NonNull int[], @NonNull int[]);
+    method public static int mismatch(@NonNull int[], int, int, @NonNull int[], int, int);
+    method public static int mismatch(@NonNull long[], @NonNull long[]);
+    method public static int mismatch(@NonNull long[], int, int, @NonNull long[], int, int);
+    method public static int mismatch(@NonNull float[], @NonNull float[]);
+    method public static int mismatch(@NonNull float[], int, int, @NonNull float[], int, int);
+    method public static int mismatch(@NonNull double[], @NonNull double[]);
+    method public static int mismatch(@NonNull double[], int, int, @NonNull double[], int, int);
+    method public static int mismatch(@NonNull Object[], @NonNull Object[]);
+    method public static int mismatch(@NonNull Object[], int, int, @NonNull Object[], int, int);
+    method public static <T> int mismatch(@NonNull T[], @NonNull T[], @NonNull java.util.Comparator<? super T>);
+    method public static <T> int mismatch(@NonNull T[], int, int, @NonNull T[], int, int, @NonNull java.util.Comparator<? super T>);
     method public static <T> void parallelPrefix(@NonNull T[], @NonNull java.util.function.BinaryOperator<T>);
     method public static <T> void parallelPrefix(@NonNull T[], int, int, @NonNull java.util.function.BinaryOperator<T>);
     method public static void parallelPrefix(@NonNull long[], @NonNull java.util.function.LongBinaryOperator);
@@ -14238,6 +14325,7 @@
     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
     method public boolean offer(E);
     method public boolean offer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
@@ -14478,7 +14566,7 @@
     method public final boolean isEmpty();
     method @NonNull public java.util.Iterator<K> iterator();
     method public boolean remove(@NonNull Object);
-    method public final boolean removeAll(@NonNull java.util.Collection<?>);
+    method public boolean removeAll(@NonNull java.util.Collection<?>);
     method public final boolean retainAll(@NonNull java.util.Collection<?>);
     method public final int size();
     method @NonNull public java.util.Spliterator<K> spliterator();
@@ -14494,6 +14582,7 @@
     method public void addLast(E);
     method public java.util.Iterator<E> descendingIterator();
     method public E element();
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E getFirst();
     method public E getLast();
     method public java.util.Iterator<E> iterator();
@@ -14519,6 +14608,7 @@
   public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue<E> implements java.util.Queue<E> java.io.Serializable {
     ctor public ConcurrentLinkedQueue();
     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
     method public boolean offer(E);
     method public E peek();
@@ -14808,6 +14898,7 @@
     ctor public ForkJoinPool();
     ctor public ForkJoinPool(int);
     ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
+    ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean, int, int, int, java.util.function.Predicate<? super java.util.concurrent.ForkJoinPool>, long, java.util.concurrent.TimeUnit);
     method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
     method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public static java.util.concurrent.ForkJoinPool commonPool();
@@ -14934,6 +15025,7 @@
     method public java.util.Iterator<E> descendingIterator();
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E getFirst();
     method public E getLast();
     method public java.util.Iterator<E> iterator();
@@ -14974,6 +15066,7 @@
     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
     method public boolean offer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public boolean offer(E);
@@ -14991,6 +15084,7 @@
     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public int getWaitingConsumerCount();
     method public boolean hasWaitingConsumer();
     method public java.util.Iterator<E> iterator();
@@ -15040,6 +15134,7 @@
     method public java.util.Comparator<? super E> comparator();
     method public int drainTo(java.util.Collection<? super E>);
     method public int drainTo(java.util.Collection<? super E>, int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public java.util.Iterator<E> iterator();
     method public boolean offer(E);
     method public boolean offer(E, long, java.util.concurrent.TimeUnit);
@@ -15137,6 +15232,29 @@
     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
   }
 
+  public class SubmissionPublisher<T> implements java.lang.AutoCloseable java.util.concurrent.Flow.Publisher<T> {
+    ctor public SubmissionPublisher(java.util.concurrent.Executor, int, java.util.function.BiConsumer<? super java.util.concurrent.Flow.Subscriber<? super T>,? super java.lang.Throwable>);
+    ctor public SubmissionPublisher(java.util.concurrent.Executor, int);
+    ctor public SubmissionPublisher();
+    method public void close();
+    method public void closeExceptionally(Throwable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> consume(java.util.function.Consumer<? super T>);
+    method public int estimateMaximumLag();
+    method public long estimateMinimumDemand();
+    method public Throwable getClosedException();
+    method public java.util.concurrent.Executor getExecutor();
+    method public int getMaxBufferCapacity();
+    method public int getNumberOfSubscribers();
+    method public java.util.List<java.util.concurrent.Flow.Subscriber<? super T>> getSubscribers();
+    method public boolean hasSubscribers();
+    method public boolean isClosed();
+    method public boolean isSubscribed(java.util.concurrent.Flow.Subscriber<? super T>);
+    method public int offer(T, java.util.function.BiPredicate<java.util.concurrent.Flow.Subscriber<? super T>,? super T>);
+    method public int offer(T, long, java.util.concurrent.TimeUnit, java.util.function.BiPredicate<java.util.concurrent.Flow.Subscriber<? super T>,? super T>);
+    method public int submit(T);
+    method public void subscribe(java.util.concurrent.Flow.Subscriber<? super T>);
+  }
+
   public class SynchronousQueue<E> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingQueue<E> java.io.Serializable {
     ctor public SynchronousQueue();
     ctor public SynchronousQueue(boolean);
@@ -15178,7 +15296,7 @@
     method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method protected void beforeExecute(Thread, Runnable);
     method public void execute(Runnable);
-    method protected void finalize();
+    method @Deprecated protected void finalize();
     method public int getActiveCount();
     method public long getCompletedTaskCount();
     method public int getCorePoolSize();
@@ -15229,9 +15347,12 @@
 
   public enum TimeUnit {
     method public long convert(long, java.util.concurrent.TimeUnit);
+    method public long convert(java.time.Duration);
+    method public static java.util.concurrent.TimeUnit of(java.time.temporal.ChronoUnit);
     method public void sleep(long) throws java.lang.InterruptedException;
     method public void timedJoin(Thread, long) throws java.lang.InterruptedException;
     method public void timedWait(Object, long) throws java.lang.InterruptedException;
+    method public java.time.temporal.ChronoUnit toChronoUnit();
     method public long toDays(long);
     method public long toHours(long);
     method public long toMicros(long);
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 15741a7..ce54d56 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -226,6 +226,7 @@
 
   public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader {
     ctor public DelegateLastClassLoader(String, String, ClassLoader, ClassLoader[]);
+    ctor public DelegateLastClassLoader(String, String, ClassLoader, ClassLoader[], ClassLoader[]);
   }
 
   @Deprecated public final class DexFile {
@@ -246,6 +247,7 @@
 
   public class PathClassLoader extends dalvik.system.BaseDexClassLoader {
     ctor public PathClassLoader(@NonNull String, @Nullable String, @Nullable ClassLoader, @Nullable ClassLoader[]);
+    ctor public PathClassLoader(@NonNull String, @Nullable String, @Nullable ClassLoader, @Nullable ClassLoader[], @Nullable ClassLoader[]);
   }
 
   public final class RuntimeHooks {
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index ee9c057..5fbf585 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -73,6 +73,19 @@
     protected final ClassLoader[] sharedLibraryLoaders;
 
     /**
+     * Array of ClassLoaders identical to {@code sharedLibraryLoaders} except that these library
+     * loaders are always checked after the {@code pathList} when looking up classes and resources.
+     *
+     * The placement of a library into this group is done by the OEM and cannot be configured by
+     * an App.
+     *
+     * <p>{@code null} if the class loader has no shared library.
+     *
+     * @hide
+     */
+    protected final ClassLoader[] sharedLibraryLoadersAfter;
+
+    /**
      * Constructs an instance.
      * Note that all the *.jar and *.apk files from {@code dexPath} might be
      * first extracted in-memory before the code is loaded. This can be avoided
@@ -89,7 +102,7 @@
      */
     public BaseDexClassLoader(String dexPath, File optimizedDirectory,
             String librarySearchPath, ClassLoader parent) {
-        this(dexPath, librarySearchPath, parent, null, false);
+        this(dexPath, librarySearchPath, parent, null, null, false);
     }
 
     /**
@@ -98,7 +111,7 @@
     @UnsupportedAppUsage
     public BaseDexClassLoader(String dexPath, File optimizedDirectory,
             String librarySearchPath, ClassLoader parent, boolean isTrusted) {
-        this(dexPath, librarySearchPath, parent, null, isTrusted);
+        this(dexPath, librarySearchPath, parent, null, null, isTrusted);
     }
 
     /**
@@ -106,10 +119,19 @@
      */
     public BaseDexClassLoader(String dexPath,
             String librarySearchPath, ClassLoader parent, ClassLoader[] libraries) {
-        this(dexPath, librarySearchPath, parent, libraries, false);
+        this(dexPath, librarySearchPath, parent, libraries, null, false);
     }
 
     /**
+     * @hide
+     */
+    public BaseDexClassLoader(String dexPath, String librarySearchPath,
+            ClassLoader parent, ClassLoader[] libraries, ClassLoader[] librariesAfter) {
+        this(dexPath, librarySearchPath, parent, libraries, librariesAfter, false);
+    }
+
+
+    /**
      * BaseDexClassLoader implements the Android
      * <a href=https://developer.android.com/guide/topics/manifest/uses-library-element>
      * shared libraries</a> feature by changing the typical parent delegation mechanism
@@ -119,11 +141,15 @@
      * after the parent.
      * The shared library loaders are always checked before the {@code pathList} when looking
      * up classes and resources.
+     * <p>
+     * The shared library loaders defined in sharedLibraryLoadersAfter are always checked
+     * <b>after</b> the {@code pathList}
      *
      * @hide
      */
     public BaseDexClassLoader(String dexPath,
             String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders,
+            ClassLoader[] sharedLibraryLoadersAfter,
             boolean isTrusted) {
         super(parent);
         // Setup shared libraries before creating the path list. ART relies on the class loader
@@ -133,6 +159,9 @@
                 : Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length);
         this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
 
+        this.sharedLibraryLoadersAfter = sharedLibraryLoadersAfter == null
+                ? null
+                : Arrays.copyOf(sharedLibraryLoadersAfter, sharedLibraryLoadersAfter.length);
         // Run background verification after having set 'pathList'.
         this.pathList.maybeRunBackgroundVerification(this);
 
@@ -192,6 +221,7 @@
     public BaseDexClassLoader(ByteBuffer[] dexFiles, String librarySearchPath, ClassLoader parent) {
         super(parent);
         this.sharedLibraryLoaders = null;
+        this.sharedLibraryLoadersAfter = null;
         this.pathList = new DexPathList(this, librarySearchPath);
         this.pathList.initByteBufferDexPath(dexFiles);
         // Run background verification after having set 'pathList'.
@@ -213,6 +243,18 @@
         // this classloader operates on.
         List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
         Class c = pathList.findClass(name, suppressedExceptions);
+        if (c != null) {
+            return c;
+        }
+        // Now, check whether the class is present in the "after" shared libraries.
+        if (sharedLibraryLoadersAfter != null) {
+            for (ClassLoader loader : sharedLibraryLoadersAfter) {
+                try {
+                    return loader.loadClass(name);
+                } catch (ClassNotFoundException ignored) {
+                }
+            }
+        }
         if (c == null) {
             ClassNotFoundException cnfe = new ClassNotFoundException(
                     "Didn't find class \"" + name + "\" on path: " + pathList);
@@ -268,28 +310,59 @@
                 }
             }
         }
-        return pathList.findResource(name);
+        URL url = pathList.findResource(name);
+        if (url != null) {
+            return url;
+        }
+        if (sharedLibraryLoadersAfter != null) {
+            for (ClassLoader loader : sharedLibraryLoadersAfter) {
+                URL url2 = loader.getResource(name);
+                if (url2 != null) {
+                    return url2;
+                }
+            }
+        }
+        return null;
     }
 
     @Override
     protected Enumeration<URL> findResources(String name) {
         Enumeration<URL> myResources = pathList.findResources(name);
-        if (sharedLibraryLoaders == null) {
+        if (sharedLibraryLoaders == null && sharedLibraryLoadersAfter == null) {
           return myResources;
         }
 
+        int sharedLibraryLoadersCount =
+                (sharedLibraryLoaders != null) ? sharedLibraryLoaders.length : 0;
+        int sharedLibraryLoadersAfterCount =
+                (sharedLibraryLoadersAfter != null) ? sharedLibraryLoadersAfter.length : 0;
+
         Enumeration<URL>[] tmp =
-            (Enumeration<URL>[]) new Enumeration<?>[sharedLibraryLoaders.length + 1];
+                (Enumeration<URL>[]) new Enumeration<?>[sharedLibraryLoadersCount +
+                        sharedLibraryLoadersAfterCount
+                        + 1];
+        // First add sharedLibrary resources.
         // This will add duplicate resources if a shared library is loaded twice, but that's ok
         // as we don't guarantee uniqueness.
-        for (int i = 0; i < sharedLibraryLoaders.length; i++) {
+        int i = 0;
+        for (; i < sharedLibraryLoadersCount; i++) {
             try {
                 tmp[i] = sharedLibraryLoaders[i].getResources(name);
             } catch (IOException e) {
                 // Ignore.
             }
         }
-        tmp[sharedLibraryLoaders.length] = myResources;
+        // Then add resource from this dex path.
+        tmp[i++] = myResources;
+
+        // Finally add resources from shared libraries that are to be loaded after.
+        for (int j = 0; j < sharedLibraryLoadersAfterCount; i++, j++) {
+            try {
+                tmp[i] = sharedLibraryLoadersAfter[j].getResources(name);
+            } catch (IOException e) {
+                // Ignore.
+            }
+        }
         return new CompoundEnumeration<>(tmp);
     }
 
diff --git a/dalvik/src/main/java/dalvik/system/DelegateLastClassLoader.java b/dalvik/src/main/java/dalvik/system/DelegateLastClassLoader.java
index f5e40b6..25a9557 100644
--- a/dalvik/src/main/java/dalvik/system/DelegateLastClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/DelegateLastClassLoader.java
@@ -136,7 +136,43 @@
     public DelegateLastClassLoader(
             String dexPath, String librarySearchPath, ClassLoader parent,
             ClassLoader[] sharedLibraryLoaders) {
-        super(dexPath, librarySearchPath, parent, sharedLibraryLoaders);
+        this(dexPath, librarySearchPath, parent, sharedLibraryLoaders, null);
+    }
+
+    /**
+     * Creates a {@code DelegateLastClassLoader} that operates on a given {@code dexPath}
+     * and a {@code librarySearchPath}.
+     *
+     * The {@code dexPath} should consist of one or more of the following, separated by
+     * {@code File.pathSeparator}, which is {@code ":"} on Android.
+     *
+     * <ul>
+     * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as well as arbitrary
+     * resources.
+     * <li>Raw ".dex" files (not inside a zip file).
+     * </ul>
+     *
+     * @param dexPath the list of jar/apk files containing classes and resources, delimited by
+     *                {@code File.pathSeparator}, which defaults to {@code ":"} on Android.
+     * @param librarySearchPath the list of directories containing native libraries, delimited
+     *                          by {@code File.pathSeparator}; may be {@code null}.
+     * @param parent the parent class loader. May be {@code null} for the boot classloader.
+     * @param sharedLibraryLoaders class loaders of Java shared libraries
+     *                             used by this new class loader. The shared library loaders are
+     *                             always checked before the {@code dexPath} when looking
+     *                             up classes and resources.
+     * @param sharedLibraryLoadersAfter class loaders of Java shared libraries
+     *                             used by this new class loader. These shared library loaders are
+     *                             always checked <b>after</b> the {@code dexPath} when looking
+     *                             up classes and resources.
+     *
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public DelegateLastClassLoader(
+            String dexPath, String librarySearchPath, ClassLoader parent,
+            ClassLoader[] sharedLibraryLoaders, ClassLoader[] sharedLibraryLoadersAfter) {
+        super(dexPath, librarySearchPath, parent, sharedLibraryLoaders, sharedLibraryLoadersAfter);
         // Delegating is the default behavior.
         this.delegateResourceLoading = true;
     }
diff --git a/dalvik/src/main/java/dalvik/system/PathClassLoader.java b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
index 2cd3b61..5174d05 100644
--- a/dalvik/src/main/java/dalvik/system/PathClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
@@ -103,6 +103,46 @@
     public PathClassLoader(
             @NonNull String dexPath, @Nullable String librarySearchPath, @Nullable ClassLoader parent,
             @Nullable ClassLoader[] sharedLibraryLoaders) {
-        super(dexPath, librarySearchPath, parent, sharedLibraryLoaders);
+        this(dexPath, librarySearchPath, parent, sharedLibraryLoaders, null);
+    }
+
+    /**
+     * Creates a {@code PathClassLoader} that operates on two given
+     * lists of files and directories. The entries of the first list
+     * should be one of the following:
+     *
+     * <ul>
+     * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as
+     * well as arbitrary resources.
+     * <li>Raw ".dex" files (not inside a zip file).
+     * </ul>
+     *
+     * The entries of the second list should be directories containing
+     * native library files.
+     *
+     * @param dexPath the list of jar/apk files containing classes and
+     * resources, delimited by {@code File.pathSeparator}, which
+     * defaults to {@code ":"} on Android
+     * @param librarySearchPath the list of directories containing native
+     * libraries, delimited by {@code File.pathSeparator}; may be
+     * {@code null}
+     * @param parent the parent class loader
+     * @param sharedLibraryLoaders class loaders of Java shared libraries
+     * used by this new class loader. The shared library loaders are always
+     * checked before the {@code dexPath} when looking
+     * up classes and resources.
+     * @param sharedLibraryLoadersAfter class loaders of Java shared libraries
+     * used by this new class loader. These shared library loaders are always
+     * checked <b>after</b> the {@code dexPath} when looking
+     * up classes and resources.
+     *
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public PathClassLoader(
+            @NonNull String dexPath, @Nullable String librarySearchPath,
+            @Nullable ClassLoader parent, @Nullable ClassLoader[] sharedLibraryLoaders,
+            @Nullable ClassLoader[] sharedLibraryLoadersAfter) {
+        super(dexPath, librarySearchPath, parent, sharedLibraryLoaders, sharedLibraryLoadersAfter);
     }
 }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
index 601d522..bd5c687 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
@@ -122,7 +122,7 @@
 
         // regression for HARMONY-1195
         try {
-            os = new PrintStream(bos, true, null);
+            os = new PrintStream(bos, true, (String) null);
             fail("Should throw NPE");
         } catch (NullPointerException e) {
         }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/spi/AbstractSelectableChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/spi/AbstractSelectableChannelTest.java
index 31124ce..cb3c01d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/spi/AbstractSelectableChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/spi/AbstractSelectableChannelTest.java
@@ -220,7 +220,7 @@
         // if channel closed
         msc.close();
         try {
-            msc.register(acceptSelector, SelectionKey.OP_READ, null);
+            msc.register(acceptSelector, SelectionKey.OP_ACCEPT, null);
             fail("Should throw ClosedChannelException");
         } catch (ClosedChannelException e) {
             // expected
diff --git a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
index 28517aa..53e0398 100644
--- a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
@@ -147,7 +147,7 @@
         assertFalse(f.isCancelled());
         assertTrue(f.isDone());
         assertTrue(f.isCompletedExceptionally());
-        assertTrue(f.toString().contains("[Completed exceptionally]"));
+        assertTrue(f.toString().contains("[Completed exceptionally:"));
     }
 
     void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
@@ -202,7 +202,7 @@
         assertTrue(f.isDone());
         assertTrue(f.isCompletedExceptionally());
         assertTrue(f.isCancelled());
-        assertTrue(f.toString().contains("[Completed exceptionally]"));
+        assertTrue(f.toString().contains("[Completed exceptionally:"));
     }
 
     /**
@@ -349,12 +349,12 @@
 
         f = new CompletableFuture<String>();
         assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
-        assertTrue(f.toString().contains("[Completed exceptionally]"));
+        assertTrue(f.toString().contains("[Completed exceptionally:"));
 
         for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
             f = new CompletableFuture<String>();
             assertTrue(f.cancel(mayInterruptIfRunning));
-            assertTrue(f.toString().contains("[Completed exceptionally]"));
+            assertTrue(f.toString().contains("[Completed exceptionally:"));
         }
     }
 
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
index e763ae4..194dd58 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
@@ -834,9 +834,7 @@
                                             1, 1, MILLISECONDS));
         periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
                                                1, 1, MILLISECONDS));
-        // Android-changed: Use a longer delay to ensure task does not expire
-        // delayeds.add(p.schedule(task, 1, MILLISECONDS));
-        delayeds.add(p.schedule(task, LONG_DELAY_MS, MILLISECONDS));
+        delayeds.add(p.schedule(task, 1, MILLISECONDS));
 
         assertTrue(p.getQueue().containsAll(periodics));
         assertTrue(p.getQueue().containsAll(delayeds));
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
index 8f65c84..81f7370 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
@@ -783,9 +783,7 @@
                                             1, 1, MILLISECONDS));
         periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
                                                1, 1, MILLISECONDS));
-        // Android-changed: Use a longer delay to ensure task does not expire
-        // delayeds.add(p.schedule(task, 1, MILLISECONDS));
-        delayeds.add(p.schedule(task, LONG_DELAY_MS, MILLISECONDS));
+        delayeds.add(p.schedule(task, 1, MILLISECONDS));
 
         assertTrue(p.getQueue().containsAll(periodics));
         assertTrue(p.getQueue().containsAll(delayeds));
diff --git a/lint-baseline.xml b/lint-baseline.xml
index 0b45784..28748f2 100644
--- a/lint-baseline.xml
+++ b/lint-baseline.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+
     <issue
         id="NewApi"
         message="Class requires API level 32 (current min is 31): `java.lang.invoke.VarHandle`"
@@ -7,7 +8,7 @@
         errorLine2="                                          ~~~~~~~~~">
         <location
             file="libcore/libart/src/main/java/java/lang/invoke/ArrayElementVarHandle.java"
-            line="27"
+            line="26"
             column="43"/>
     </issue>
 
@@ -51,7 +52,7 @@
         errorLine2="                               ~~~~~~~~~">
         <location
             file="libcore/ojluni/src/main/java/java/lang/invoke/MethodHandles.java"
-            line="900"
+            line="901"
             column="32"/>
     </issue>
 
@@ -62,7 +63,7 @@
         errorLine2="                        ~~~~~~~~~">
         <location
             file="libcore/ojluni/src/main/java/java/lang/invoke/MethodHandles.java"
-            line="2470"
+            line="2471"
             column="25"/>
     </issue>
 
@@ -73,8 +74,108 @@
         errorLine2="                                                             ~~~~~~~~~">
         <location
             file="libcore/ojluni/src/main/java/java/lang/invoke/MethodHandles.java"
-            line="2477"
+            line="2478"
             column="62"/>
     </issue>
 
+
+    <issue
+        id="NewApi"
+        message="Class requires API level 32 (current min is 31): `java.security.cert.URICertStoreParameters`"
+        errorLine1="        if (p == null || (!(p instanceof URICertStoreParameters))) {"
+        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java"
+            line="127"
+            column="42"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Class requires API level 32 (current min is 31): `java.security.cert.URICertStoreParameters`"
+        errorLine1="        URICertStoreParameters other = (URICertStoreParameters)p;"
+        errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java"
+            line="135"
+            column="41"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+        errorLine1="            return TWO;"
+        errorLine2="                   ~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+            line="864"
+            column="20" />
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+        errorLine1="                        result = result.add(TWO);"
+        errorLine2="                                            ~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+            line="882"
+            column="45" />
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+        errorLine1="                result = result.add(TWO);"
+        errorLine2="                                    ~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+            line="895"
+            column="37" />
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+        errorLine1="                z = z.modPow(TWO, this);"
+        errorLine2="                             ~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+            line="1112"
+            column="30" />
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+        errorLine1="        if (w.equals(TWO))"
+        errorLine2="                     ~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+            line="3821"
+            column="22" />
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+        errorLine1="        new BigDecimal(BigInteger.TWO,        2,  0, 1),"
+        errorLine2="                       ~~~~~~~~~~~~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/math/BigDecimal.java"
+            line="296"
+            column="24" />
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+        errorLine1="                rb = BigInteger.TWO.pow(exponent).multiply(compactVal);"
+        errorLine2="                     ~~~~~~~~~~~~~~">
+        <location
+            file="libcore/ojluni/src/main/java/java/math/BigDecimal.java"
+            line="956"
+            column="22" />
+    </issue>
+
 </issues>
diff --git a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
index 7d3b6f2..064e042 100644
--- a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
@@ -17,6 +17,7 @@
 package libcore.dalvik.system;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -234,6 +235,62 @@
     }
 
     @Test
+    public void testReporting_withSharedLibraries_loaded_after() throws Exception {
+        final ClassLoader parent = ClassLoader.getSystemClassLoader();
+        final ClassLoader sharedLoaders[] = new ClassLoader[] {
+                new PathClassLoader(jar2.getPath(), /* librarySearchPath */ null, parent),
+        };
+        // Reset so we don't get load reports from creating the shared library CL
+        reporter.reset();
+
+        BaseDexClassLoader bdcl = new PathClassLoader(
+                jar.getPath(), null, parent, null, sharedLoaders);
+
+        assertEquals(1, reporter.loadedDexMapping.size());
+
+        String[] contexts = separateSystemClassLoaderContext(
+                reporter.loadedDexMapping.get(jar.getPath()));
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
+        // Verify the context for the loaded dex files. The system class loader should be part
+        // of the shared library class loader.
+        assertEquals("PCL[]{~PCL[" + jar2.getPath() + "];" + contexts[1] + "}",
+                contexts[0]);
+    }
+
+    @Test
+    public void testReporting_withSharedLibraries_loaded_before_and_after() throws Exception {
+        final ClassLoader parent = ClassLoader.getSystemClassLoader();
+        final String sharedJarPath = resourcesMap.get("parent.jar").getAbsolutePath();
+        final String sharedJarPath2 = resourcesMap.get("child.jar").getAbsolutePath();
+        final ClassLoader sharedLoaders[] = new ClassLoader[] {
+                new PathClassLoader(sharedJarPath, /* librarySearchPath */ null, parent),
+        };
+        final ClassLoader sharedLoadersAfter[] = new ClassLoader[] {
+                new PathClassLoader(sharedJarPath2, /* librarySearchPath */ null, parent),
+        };
+        // Reset so we don't get load reports from creating the shared library CL
+        reporter.reset();
+
+        BaseDexClassLoader bdcl = new PathClassLoader(jar.getPath(), null, parent, sharedLoaders,
+                sharedLoadersAfter);
+
+        assertEquals(1, reporter.loadedDexMapping.size());
+
+        String[] contexts = separateSystemClassLoaderContext(
+                reporter.loadedDexMapping.get(jar.getPath()));
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
+        // Verify the context for the loaded dex files. The system class loader should be part
+        // of the shared library class loader.
+        assertEquals("PCL[]{PCL[" + sharedJarPath + "];" + contexts[1]
+                        + "#~PCL[" + sharedJarPath2 + "];" + contexts[1] + "}",
+                contexts[0]);
+    }
+
+    @Test
     public void testReporting_multipleJars_withSharedLibraries() throws Exception {
         final ClassLoader parent = ClassLoader.getSystemClassLoader();
         final String sharedJarPath = resourcesMap.get("parent.jar").getAbsolutePath();
@@ -277,6 +334,49 @@
     }
 
     @Test
+    public void testReporting_multipleJars_withSharedLibraries_loaded_after() throws Exception {
+        final ClassLoader parent = ClassLoader.getSystemClassLoader();
+        final String sharedJarPath = resourcesMap.get("parent.jar").getAbsolutePath();
+        final ClassLoader sharedLoaders[] = new ClassLoader[] {
+                new PathClassLoader(sharedJarPath, /* librarySearchPath */ null, parent),
+        };
+        // Reset so we don't get load reports from creating the shared library CL
+        reporter.reset();
+
+        BaseDexClassLoader bdcl = new PathClassLoader(
+                String.join(File.pathSeparator, jar.getPath(), jar2.getPath()),
+                null, parent, null, sharedLoaders);
+
+        assertEquals(2, reporter.loadedDexMapping.size());
+
+
+        // Verify the first jar.
+        String[] contexts = separateSystemClassLoaderContext(
+                reporter.loadedDexMapping.get(jar.getPath()));
+        String contextSuffix = "{~PCL[" + sharedJarPath + "];" + contexts[1] + "}";
+
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
+        // Verify the context for the loaded dex files.
+        assertEquals("PCL[]" + contextSuffix, contexts[0]);
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
+
+        // Verify the second jar.
+        String[] contexts2 = separateSystemClassLoaderContext(
+                reporter.loadedDexMapping.get(jar2.getPath()));
+        String contextSuffix2 = "{~PCL[" + sharedJarPath + "];" + contexts2[1] + "}";
+
+        // Verify the context for the loaded dex files.
+        assertEquals("PCL[" + jar.getPath() + "]" + contextSuffix2, contexts2[0]);
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts2[1].startsWith("PCL[")) ;
+    }
+
+    @Test
     public void testReporting_emptyPath() throws Exception {
         BaseDexClassLoader cl1 = new PathClassLoader("", ClassLoader.getSystemClassLoader());
         assertEquals(Map.<String, String>of(), reporter.loadedDexMapping);
@@ -345,6 +445,16 @@
         loader = new DelegateLastClassLoader("", null, parent, sharedLibraries);
         assertEquals("parent", readResource(loader, "resource.txt"));
         checkResources(loader);
+
+        // PCL[]{~PCL[parent.jar]#~PCL[child.jar]}
+        loader = new PathClassLoader("", null, parent, null, sharedLibraries);
+        assertEquals("parent", readResource(loader, "resource.txt"));
+        checkResources(loader);
+
+        // DLC[]{~PCL[parent.jar]#~PCL[child.jar]}
+        loader = new DelegateLastClassLoader("", null, parent, null, sharedLibraries);
+        assertEquals("parent", readResource(loader, "resource.txt"));
+        checkResources(loader);
     }
 
     @Test
@@ -370,6 +480,16 @@
         loader = new DelegateLastClassLoader("", null, parent, sharedLibraries);
         assertEquals("child", readResource(loader, "resource.txt"));
         checkResources(loader);
+
+        // PCL[]{~PCL[child.jar]#~PCL[parent.jar]}
+        loader = new PathClassLoader("", null, parent, null, sharedLibraries);
+        assertEquals("child", readResource(loader, "resource.txt"));
+        checkResources(loader);
+
+        // DLC[]{~PCL[child.jar]#~PCL[parent.jar]}
+        loader = new DelegateLastClassLoader("", null, parent, null, sharedLibraries);
+        assertEquals("child", readResource(loader, "resource.txt"));
+        checkResources(loader);
     }
 
     @Test
@@ -398,6 +518,16 @@
         loader = new DelegateLastClassLoader("", null, parent, sharedLibraryLevel1);
         assertEquals("parent", readResource(loader, "resource.txt"));
         checkResources(loader);
+
+        // PCL[]{~PCL[child.jar]{PCL[parent.jar]}}
+        loader = new PathClassLoader("", null, parent, null, sharedLibraryLevel1);
+        assertEquals("parent", readResource(loader, "resource.txt"));
+        checkResources(loader);
+
+        // DLC[]{~PCL[child.jar]{PCL[parent.jar]}}
+        loader = new DelegateLastClassLoader("", null, parent, null, sharedLibraryLevel1);
+        assertEquals("parent", readResource(loader, "resource.txt"));
+        checkResources(loader);
     }
 
     @Test
@@ -426,6 +556,16 @@
         loader = new DelegateLastClassLoader("", null, parent, sharedLibraryLevel1);
         assertEquals("child", readResource(loader, "resource.txt"));
         checkResources(loader);
+
+        // PCL[]{~PCL[parent.jar]{PCL[child.jar]}}
+        loader = new PathClassLoader("", null, parent, null, sharedLibraryLevel1);
+        assertEquals("child", readResource(loader, "resource.txt"));
+        checkResources(loader);
+
+        // DLC[]{~PCL[parent.jar]{PCL[child.jar]}}
+        loader = new DelegateLastClassLoader("", null, parent, null, sharedLibraryLevel1);
+        assertEquals("child", readResource(loader, "resource.txt"));
+        checkResources(loader);
     }
 
     @Test
@@ -448,12 +588,163 @@
         // Check that the parent was queried first.
         assertEquals("parent", readResource(pathLoader, "resource.txt"));
 
+        // PCL[]{~PCL[child.jar]};PCL[parent.jar]
+        pathLoader = new PathClassLoader("", null, parent, null, sharedLibrary);
+
+        // Check that the parent was queried first.
+        assertEquals("parent", readResource(pathLoader, "resource.txt"));
+
         // DLC[]{PCL[child.jar]};PCL[parent.jar]
         ClassLoader delegateLast = new DelegateLastClassLoader("", null, parent, sharedLibrary);
 
         // Check that the shared library was queried first.
         assertEquals("child", readResource(delegateLast, "resource.txt"));
 
+        // DLC[]{~PCL[child.jar]};PCL[parent.jar]
+        delegateLast = new DelegateLastClassLoader("", null, parent, null, sharedLibrary);
+
+        // Check that the shared library was queried first.
+        assertEquals("child", readResource(delegateLast, "resource.txt"));
+
+    }
+
+    @Test
+    public void testGetResourceSharedLibraries6() throws Exception {
+        File parentPath = resourcesMap.get("parent.jar");
+        File childPath = resourcesMap.get("child.jar");
+        assertTrue(parentPath != null);
+        assertTrue(childPath != null);
+
+        ClassLoader parent = Object.class.getClassLoader();
+
+        ClassLoader[] sharedLibrary = {
+                new PathClassLoader(childPath.getAbsolutePath(), null, parent),
+        };
+
+        // PCL[]{PCL[child.jar]};PCL[parent.jar]
+        ClassLoader pathLoader = new PathClassLoader(
+                parentPath.getAbsolutePath(), null, parent, sharedLibrary);
+
+        // Check that the parent was queried first.
+        assertEquals("child", readResource(pathLoader, "resource.txt"));
+
+        // PCL[]{~PCL[child.jar]};PCL[parent.jar]
+        pathLoader = new PathClassLoader(
+                parentPath.getAbsolutePath(), null, parent, null, sharedLibrary);
+
+        // Check that the parent was queried first.
+        assertEquals("parent", readResource(pathLoader, "resource.txt"));
+        // confirm resource from shard lib is available
+        checkResources(pathLoader);
+
+        // PCL[]{~PCL[child.jar]};PCL[]
+        pathLoader = new PathClassLoader("", null, parent, null, sharedLibrary);
+        // Check that the shared library was queried last.
+        assertEquals("child", readResource(pathLoader, "resource.txt"));
+
+        // DLC[]{PCL[child.jar]};PCL[parent.jar]
+        ClassLoader delegateLast = new DelegateLastClassLoader(
+                parentPath.getAbsolutePath(), null, parent, sharedLibrary);
+
+        // Check that the shared library was queried first.
+        assertEquals("child", readResource(delegateLast, "resource.txt"));
+
+        // DLC[]{~PCL[child.jar]};PCL[parent.jar]
+        delegateLast = new DelegateLastClassLoader(
+                parentPath.getAbsolutePath(), null, parent, null, sharedLibrary);
+
+        // Check that the shared library was queried first.
+        assertEquals("parent", readResource(delegateLast, "resource.txt"));
+        // confirm resource from shard lib is available
+        checkResources(delegateLast);
+
+        // DLC[]{~PCL[child.jar]};PCL[]
+        delegateLast = new DelegateLastClassLoader("", null, parent, null, sharedLibrary);
+        // Check that the shared library was queried last.
+        assertEquals("child", readResource(delegateLast, "resource.txt"));
+
+    }
+
+    @Test
+    public void testGetResourceSharedLibraries7() throws Exception {
+        File parentPath = resourcesMap.get("parent.jar");
+        File childPath = resourcesMap.get("child.jar");
+        assertTrue(parentPath != null);
+        assertTrue(childPath != null);
+
+        ClassLoader parent = Object.class.getClassLoader();
+
+        ClassLoader[] sharedLibrary1 = {
+                new PathClassLoader(parentPath.getAbsolutePath(), null, parent),
+        };
+
+        ClassLoader[] sharedLibrary2 = {
+                new PathClassLoader(childPath.getAbsolutePath(), null, parent),
+        };
+
+        // PCL[]{PCL[parent.jar]#~PCL[child.jar]}
+        ClassLoader loader = new PathClassLoader("", null, parent, sharedLibrary1, sharedLibrary2);
+        assertEquals("parent", readResource(loader, "resource.txt"));
+        checkResources(loader);
+
+        // PCL[]{PCL[child.jar]#~PCL[parent.jar]}
+        loader = new PathClassLoader("", null, parent, sharedLibrary2, sharedLibrary1);
+        assertEquals("child", readResource(loader, "resource.txt"));
+        checkResources(loader);
+
+        loader = new DelegateLastClassLoader("", null, parent, sharedLibrary1, sharedLibrary2);
+        assertEquals("parent", readResource(loader, "resource.txt"));
+        checkResources(loader);
+
+        // PCL[]{PCL[child.jar]#~PCL[parent.jar]}
+        loader = new DelegateLastClassLoader("", null, parent, sharedLibrary2, sharedLibrary1);
+        assertEquals("child", readResource(loader, "resource.txt"));
+        checkResources(loader);
+    }
+
+    @Test
+    public void testLookupOrder_loadClass() throws Exception {
+        File parentPath = resourcesMap.get("parent.jar");
+        File childPath = resourcesMap.get("child.jar");
+        assertTrue(parentPath != null);
+        assertTrue(childPath != null);
+
+        ClassLoader parent = Object.class.getClassLoader();
+
+        ClassLoader[] sharedLibrary1 = {
+                new PathClassLoader(parentPath.getAbsolutePath(), null, parent),
+        };
+
+        ClassLoader[] sharedLibrary2 = {
+                new PathClassLoader(childPath.getAbsolutePath(), null, parent),
+        };
+
+        // PCL[]{PCL[parent.jar]#~PCL[child.jar]}
+        ClassLoader loader = new PathClassLoader("", null, parent, sharedLibrary1, sharedLibrary2);
+        assertEquals("A_parent", callMethod(loader, "toString", sharedLibrary1[0]));
+        Class<?> parentClass = loader.loadClass("libcore.test.delegatelast.Parent");
+        assertSame(sharedLibrary1[0], parentClass.getClassLoader());
+        Class<?> childClass = loader.loadClass("libcore.test.delegatelast.Child");
+        assertSame(sharedLibrary2[0], childClass.getClassLoader());
+
+
+        // Note that the order is reversed here. "parent" is looked up before "child".
+        loader = new PathClassLoader("", null, parent, sharedLibrary2, sharedLibrary1);
+        assertEquals("A_child", callMethod(loader, "toString", sharedLibrary2[0]));
+        parentClass = loader.loadClass("libcore.test.delegatelast.Parent");
+        assertSame(sharedLibrary1[0], parentClass.getClassLoader());
+        childClass = loader.loadClass("libcore.test.delegatelast.Child");
+        assertSame(sharedLibrary2[0], childClass.getClassLoader());
+    }
+
+    private static String callMethod(ClassLoader cl, String name, ClassLoader srcofclass)
+            throws Exception {
+        Class<?> clazz = cl.loadClass("libcore.test.delegatelast.A");
+        assertSame(srcofclass, clazz.getClassLoader());
+
+        Method method = clazz.getMethod(name);
+        Object obj = clazz.newInstance();
+        return (String) method.invoke(obj);
     }
 
     @Test
diff --git a/luni/src/test/java/libcore/java/lang/ThreadTest.java b/luni/src/test/java/libcore/java/lang/ThreadTest.java
index 29ed4a2..439aa9a 100644
--- a/luni/src/test/java/libcore/java/lang/ThreadTest.java
+++ b/luni/src/test/java/libcore/java/lang/ThreadTest.java
@@ -590,6 +590,8 @@
         }
     }
 
+    // BEGIN Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+    /*
     @Test
     public void onSpinWait() throws InterruptedException {
         SpinWaitThread t = new SpinWaitThread();
@@ -614,4 +616,6 @@
             done = true;
         }
     }
+     */
+    // END Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
 }
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java
new file mode 100644
index 0000000..12ec722
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ArrayBlockingQueueTest {
+
+    @Test
+    public void testForEach() {
+        int capacity = 10;
+        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(capacity);
+        for (int i = 0; i < capacity; ++i) {
+            queue.add(Integer.valueOf(i+1));
+        }
+        LongAdder adder = new LongAdder();
+        queue.forEach((Integer x) -> adder.add(x.longValue()));
+        // The size is small enough for the sum not to overflow
+        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java
new file mode 100644
index 0000000..6a6f7ea
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConcurrentLinkedDequeTest {
+
+    @Test
+    public void testForEach() {
+        int capacity = 10;
+        ConcurrentLinkedDeque<Integer> deque = new ConcurrentLinkedDeque<>();
+        for (int i = 0; i < capacity; ++i) {
+            deque.add(Integer.valueOf(i+1));
+        }
+        LongAdder adder = new LongAdder();
+        deque.forEach((Integer x) -> adder.add(x.longValue()));
+        // The size is small enough for the sum not to overflow
+        assertEquals(deque.size() * (deque.size() + 1) / 2, adder.sum());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java
new file mode 100644
index 0000000..6a1bffa
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConcurrentLinkedQueueTest {
+
+    @Test
+    public void testForEach() {
+        int capacity = 10;
+        ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
+        for (int i = 0; i < capacity; ++i) {
+            queue.add(Integer.valueOf(i+1));
+        }
+        LongAdder adder = new LongAdder();
+        queue.forEach((Integer x) -> adder.add(x.longValue()));
+        // The size is small enough for the sum not to overflow
+        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java b/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
index 80005df..29ceaebe 100644
--- a/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
+++ b/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
@@ -285,7 +285,7 @@
     public void testDoesNotRetainToArray() {
         String[] strings = { "a", "b", "c" };
         List<String> asList = Arrays.asList(strings);
-        assertEquals(String[].class, asList.toArray().getClass());
+
         CopyOnWriteArrayList<Object> objects = new CopyOnWriteArrayList<Object>(asList);
         objects.add(Boolean.TRUE);
     }
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java b/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
index 578970e..48d4170 100644
--- a/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
+++ b/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
@@ -70,4 +70,94 @@
             fail("Unexpected exception: " + t.getMessage());
         }
     }
+
+    @Test
+    public void testConstructor_withKeepAliveTime() {
+
+        try {
+            ForkJoinPool pool = new ForkJoinPool(0,
+                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+                    /*handler*/ null,
+                    /*asyncMode*/ false,
+                    /*corePoolSize*/ 10,
+                    /*maximumPoolSize*/ 10,
+                    /*minimumRunnable*/ 1,
+                    /*saturate*/ null,
+                    /*keepAliveTime*/ 60,
+                    /*unit*/ TimeUnit.SECONDS);
+            fail("Expected IllegalArgumentException when parallelism is 0");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            ForkJoinPool pool = new ForkJoinPool(-1,
+                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+                    /*handler*/ null,
+                    /*asyncMode*/ false,
+                    /*corePoolSize*/ 10,
+                    /*maximumPoolSize*/ 10,
+                    /*minimumRunnable*/ 1,
+                    /*saturate*/ null,
+                    /*keepAliveTime*/ 60,
+                    /*unit*/ TimeUnit.SECONDS);
+            fail("Expected IllegalArgumentException when parallelism is less than 0");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            ForkJoinPool pool = new ForkJoinPool(8,
+                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+                    /*handler*/ null,
+                    /*asyncMode*/ false,
+                    /*corePoolSize*/ 10,
+                    /*maximumPoolSize*/ 5,
+                    /*minimumRunnable*/ 1,
+                    /*saturate*/ null,
+                    /*keepAliveTime*/ 60,
+                    /*unit*/ TimeUnit.SECONDS);
+            fail("Expected IllegalArgumentException when maximumPoolSize is less than parallelism");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            ForkJoinPool pool = new ForkJoinPool(8,
+                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+                    /*handler*/ null,
+                    /*asyncMode*/ false,
+                    /*corePoolSize*/ 10,
+                    /*maximumPoolSize*/ 10,
+                    /*minimumRunnable*/ 1,
+                    /*saturate*/ null,
+                    /*keepAliveTime*/ 0,
+                    /*unit*/ TimeUnit.SECONDS);
+            fail("Expected IllegalArgumentException when keepAlivetime is 0");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            ForkJoinPool pool = new ForkJoinPool(8,
+                    null,
+                    /*handler*/ null,
+                    /*asyncMode*/ false,
+                    /*corePoolSize*/ 10,
+                    /*maximumPoolSize*/ 10,
+                    /*minimumRunnable*/ 1,
+                    /*saturate*/ null,
+                    /*keepAliveTime*/ 60,
+                    /*unit*/ TimeUnit.SECONDS);
+            fail("Expected NullPointerException when factory is null");
+        } catch (NullPointerException e) {
+        }
+
+        ForkJoinPool pool = new ForkJoinPool(8,
+                ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+                /*handler*/ null,
+                /*asyncMode*/ false,
+                /*corePoolSize*/ 10,
+                /*maximumPoolSize*/ 10,
+                /*minimumRunnable*/ 1,
+                /*saturate*/ null,
+                /*keepAliveTime*/ 60,
+                /*unit*/ TimeUnit.SECONDS);
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java
new file mode 100644
index 0000000..66dd942
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class LinkedBlockingDequeTest {
+
+    @Test
+    public void testForEach() {
+        int capacity = 10;
+        LinkedBlockingDeque<Integer> deque = new LinkedBlockingDeque<>();
+        for (int i = 0; i < capacity; ++i) {
+            deque.add(Integer.valueOf(i+1));
+        }
+        LongAdder adder = new LongAdder();
+        deque.forEach((Integer x) -> adder.add(x.longValue()));
+        // The size is small enough for the sum not to overflow
+        assertEquals(deque.size() * (deque.size() + 1) / 2, adder.sum());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java
new file mode 100644
index 0000000..4363988
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class LinkedBlockingQueueTest {
+
+    @Test
+    public void testForEach() {
+        int capacity = 10;
+        LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
+        for (int i = 0; i < capacity; ++i) {
+            queue.add(Integer.valueOf(i+1));
+        }
+        LongAdder adder = new LongAdder();
+        queue.forEach((Integer x) -> adder.add(x.longValue()));
+        // The size is small enough for the sum not to overflow
+        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java
new file mode 100644
index 0000000..5b09284
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class LinkedTransferQueueTest {
+
+    @Test
+    public void testForEach() {
+        int capacity = 10;
+        LinkedTransferQueue<Integer> queue = new LinkedTransferQueue<>();
+        for (int i = 0; i < capacity; ++i) {
+            queue.add(Integer.valueOf(i+1));
+        }
+        LongAdder adder = new LongAdder();
+        queue.forEach((Integer x) -> adder.add(x.longValue()));
+        // The size is small enough for the sum not to overflow
+        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java
new file mode 100644
index 0000000..ba7bc0c
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PriorityBlockingQueueTest {
+
+    @Test
+    public void testForEach() {
+        int capacity = 10;
+        PriorityBlockingQueue<Integer> queue = new PriorityBlockingQueue<>(capacity);
+        for (int i = 0; i < capacity; ++i) {
+            queue.add(Integer.valueOf(i+1));
+        }
+        LongAdder adder = new LongAdder();
+        queue.forEach((Integer x) -> adder.add(x.longValue()));
+        // The size is small enough for the sum not to overflow
+        assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+    }
+}
diff --git a/ojluni/annotations/sdk/nullability/java/io/PrintWriter.annotated.java b/ojluni/annotations/sdk/nullability/java/io/PrintWriter.annotated.java
index 531dfb0..9c3a936 100644
--- a/ojluni/annotations/sdk/nullability/java/io/PrintWriter.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/io/PrintWriter.annotated.java
@@ -41,12 +41,18 @@
 
 public PrintWriter(@libcore.util.NonNull java.io.OutputStream out, boolean autoFlush) { throw new RuntimeException("Stub!"); }
 
+public PrintWriter(@libcore.util.NonNull java.io.OutputStream out, boolean autoFlush, @libcore.util.NonNull java.nio.charset.Charset charset) { throw new RuntimeException("Stub!"); }
+
 public PrintWriter(@libcore.util.NonNull java.lang.String fileName) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
 
 public PrintWriter(@libcore.util.NonNull java.lang.String fileName, @libcore.util.NonNull java.lang.String csn) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
 
+public PrintWriter(@libcore.util.NonNull java.lang.String fileName, @libcore.util.NonNull java.nio.charset.Charset charset) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
 public PrintWriter(@libcore.util.NonNull java.io.File file) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
 
+public PrintWriter(@libcore.util.NonNull java.io.File file, @libcore.util.NonNull java.nio.charset.Charset charset) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
 public PrintWriter(@libcore.util.NonNull java.io.File file, @libcore.util.NonNull java.lang.String csn) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
 
 public void flush() { throw new RuntimeException("Stub!"); }
diff --git a/ojluni/annotations/sdk/nullability/java/math/BigInteger.annotated.java b/ojluni/annotations/sdk/nullability/java/math/BigInteger.annotated.java
index 522c3af..e8f71c4 100644
--- a/ojluni/annotations/sdk/nullability/java/math/BigInteger.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/math/BigInteger.annotated.java
@@ -28,8 +28,12 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> {
 
+    public BigInteger(byte[] val, int off, int len) { throw new RuntimeException("Stub!"); }
+
     public BigInteger(byte[] val) { throw new RuntimeException("Stub!"); }
 
+    public BigInteger(int signum, byte[] magnitude, int off, int len) { throw new RuntimeException("Stub!"); }
+
     public BigInteger(int signum, byte[] magnitude) { throw new RuntimeException("Stub!"); }
 
     public BigInteger(@libcore.util.NonNull java.lang.String val, int radix) { throw new RuntimeException("Stub!"); }
@@ -52,6 +56,8 @@
 
     @libcore.util.NonNull public static final BigInteger ONE = null;
 
+    @libcore.util.NonNull public static final java.math.BigInteger TWO = null;
+
     @libcore.util.NonNull public static final BigInteger TEN = null;
 
     @libcore.util.NonNull public BigInteger add(@libcore.util.NonNull BigInteger val) { throw new RuntimeException("Stub!"); }
@@ -76,6 +82,10 @@
 
     public int signum() { return 0; }
 
+    @libcore.util.NonNull public BigInteger sqrt() { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public BigInteger[] sqrtAndRemainder() { throw new RuntimeException("Stub!"); }
+
     @libcore.util.NonNull public BigInteger mod(@libcore.util.NonNull BigInteger m) { throw new RuntimeException("Stub!"); }
 
     @libcore.util.NonNull public BigInteger modPow(@libcore.util.NonNull BigInteger exponent, @libcore.util.NonNull BigInteger m) { throw new RuntimeException("Stub!"); }
diff --git a/ojluni/annotations/sdk/nullability/java/util/Arrays.annotated.java b/ojluni/annotations/sdk/nullability/java/util/Arrays.annotated.java
index 99dec24..891f9b9 100644
--- a/ojluni/annotations/sdk/nullability/java/util/Arrays.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/Arrays.annotated.java
@@ -169,22 +169,44 @@
 
 public static boolean equals(long @libcore.util.Nullable [] a, long @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(long @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, long @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
 public static boolean equals(int @libcore.util.Nullable [] a, int @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(int @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, int @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
 public static boolean equals(short @libcore.util.Nullable [] a, short @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(short @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, short @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
 public static boolean equals(char @libcore.util.Nullable [] a, char @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(char @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, char @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
 public static boolean equals(byte @libcore.util.Nullable [] a, byte @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(byte @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, byte @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
 public static boolean equals(boolean @libcore.util.Nullable [] a, boolean @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(boolean @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, boolean @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
 public static boolean equals(double @libcore.util.Nullable [] a, double @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(double @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, double @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
 public static boolean equals(float @libcore.util.Nullable [] a, float @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(float @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, float @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
 public static boolean equals(java.lang.@libcore.util.Nullable Object @libcore.util.Nullable [] a, java.lang.@libcore.util.Nullable Object @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
 
+public static boolean equals(java.lang.@libcore.util.Nullable java.lang.Object @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, java.lang.@libcore.util.Nullable java.lang.Object @libcore.util.NonNull[] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> boolean equals(T @libcore.util.Nullable[] a, T @libcore.util.Nullable [] a2, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static <T> boolean equals(T @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, T @libcore.util.NonNull [] b, int bFromIndex, int bToIndex, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
 public static void fill(long @libcore.util.NonNull [] a, long val) { throw new RuntimeException("Stub!"); }
 
 public static void fill(long @libcore.util.NonNull [] a, int fromIndex, int toIndex, long val) { throw new RuntimeException("Stub!"); }
@@ -353,4 +375,100 @@
 @libcore.util.NonNull public static java.util.stream.DoubleStream stream(double @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
 
 @libcore.util.NonNull public static java.util.stream.DoubleStream stream(double @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
+public static int compare(boolean @libcore.util.Nullable [] a, boolean @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(boolean @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, boolean @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(byte @libcore.util.Nullable [] a, byte @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(byte @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, byte @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(byte @libcore.util.Nullable [] a, byte @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(byte @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, byte @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(short @libcore.util.Nullable [] a, short @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(short @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, short @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(short @libcore.util.Nullable [] a, short @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(short @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, short @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(char @libcore.util.Nullable [] a, char @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(char @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, char @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(int @libcore.util.Nullable [] a, int @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(int @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, int @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(int @libcore.util.Nullable [] a, int @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(int @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, int @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(long @libcore.util.Nullable [] a, long @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(long @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, long @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(long @libcore.util.Nullable [] a, long @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(long @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, long @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(float @libcore.util.Nullable [] a, float @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(float @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, float @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(double @libcore.util.Nullable [] a, double @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(double @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, double @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> int compare(T @libcore.util.Nullable [] a, T @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> int compare(T @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, T @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> int compare(T @libcore.util.Nullable [] a, T @libcore.utill.Nullable [] b, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static <T> int compare(T @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, T @libcore.util.NonNull [] b, int bFromIndex, int bToIndex, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(boolean @libcore.util.NonNull [] a, boolean @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(boolean @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, boolean @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(byte @libcore.util.NonNull [] a, byte @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(char @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, char @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(char @libcore.util.NonNull [] a, char @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(char @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, char @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(short @libcore.util.NonNull [] a, short @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(short @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, short @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(int @libcore.util.NonNull [] a, int @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(int @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, int @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(long @libcore.util.NonNull [] a, long @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(long @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, long @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(float @libcore.util.NonNull [] a, float @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(float @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, float @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(double @libcore.util.NonNull [] a, double @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(double @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, double @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(java.lang.Object @libcore.util.NonNull [] a, java.lang.Object @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(java.lang.Object @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, java.lang.Object @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> int mismatch(T @libcore.util.NonNull [] a, T @libcore.util.NonNull [] b, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static <T> int mismatch(T @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, T @libcore.util.NonNull [] b, int bFromIndex, int bToIndex, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
 }
diff --git a/ojluni/src/main/java/java/io/FileReader.java b/ojluni/src/main/java/java/io/FileReader.java
index acc3a19..d37cd8c 100644
--- a/ojluni/src/main/java/java/io/FileReader.java
+++ b/ojluni/src/main/java/java/io/FileReader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, 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,30 +25,32 @@
 
 package java.io;
 
+import java.nio.charset.Charset;
 
 /**
- * Convenience class for reading character files.  The constructors of this
- * class assume that the default character encoding and the default byte-buffer
- * size are appropriate.  To specify these values yourself, construct an
- * InputStreamReader on a FileInputStream.
+ * Reads text from character files using a default buffer size. Decoding from bytes
+ * to characters uses either a specified {@linkplain java.nio.charset.Charset charset}
+ * or the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
  *
- * <p><code>FileReader</code> is meant for reading streams of characters.
- * For reading streams of raw bytes, consider using a
- * <code>FileInputStream</code>.
+ * <p>
+ * The {@code FileReader} is meant for reading streams of characters. For reading
+ * streams of raw bytes, consider using a {@code FileInputStream}.
  *
  * @see InputStreamReader
  * @see FileInputStream
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 public class FileReader extends InputStreamReader {
 
    /**
-    * Creates a new <tt>FileReader</tt>, given the name of the
-    * file to read from.
+    * Creates a new {@code FileReader}, given the name of the file to read,
+    * using the platform's
+    * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
     *
-    * @param fileName the name of the file to read from
+    * @param fileName the name of the file to read
     * @exception  FileNotFoundException  if the named file does not exist,
     *                   is a directory rather than a regular file,
     *                   or for some other reason cannot be opened for
@@ -59,10 +61,11 @@
     }
 
    /**
-    * Creates a new <tt>FileReader</tt>, given the <tt>File</tt>
-    * to read from.
+    * Creates a new {@code FileReader}, given the {@code File} to read,
+    * using the platform's
+    * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
     *
-    * @param file the <tt>File</tt> to read from
+    * @param file the {@code File} to read
     * @exception  FileNotFoundException  if the file does not exist,
     *                   is a directory rather than a regular file,
     *                   or for some other reason cannot be opened for
@@ -73,13 +76,47 @@
     }
 
    /**
-    * Creates a new <tt>FileReader</tt>, given the
-    * <tt>FileDescriptor</tt> to read from.
+    * Creates a new {@code FileReader}, given the {@code FileDescriptor} to read,
+    * using the platform's
+    * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
     *
-    * @param fd the FileDescriptor to read from
+    * @param fd the {@code FileDescriptor} to read
     */
     public FileReader(FileDescriptor fd) {
         super(new FileInputStream(fd));
     }
 
+   /**
+    * Creates a new {@code FileReader}, given the name of the file to read
+    * and the {@linkplain java.nio.charset.Charset charset}.
+    *
+    * @param fileName the name of the file to read
+    * @param charset the {@linkplain java.nio.charset.Charset charset}
+    * @exception  IOException  if the named file does not exist,
+    *                   is a directory rather than a regular file,
+    *                   or for some other reason cannot be opened for
+    *                   reading.
+    *
+    * @since 11
+    */
+    public FileReader(String fileName, Charset charset) throws IOException {
+        super(new FileInputStream(fileName), charset);
+    }
+
+   /**
+    * Creates a new {@code FileReader}, given the {@code File} to read and
+    * the {@linkplain java.nio.charset.Charset charset}.
+    *
+    * @param file the {@code File} to read
+    * @param charset the {@linkplain java.nio.charset.Charset charset}
+    * @exception  IOException  if the file does not exist,
+    *                   is a directory rather than a regular file,
+    *                   or for some other reason cannot be opened for
+    *                   reading.
+    *
+    * @since 11
+    */
+    public FileReader(File file, Charset charset) throws IOException {
+        super(new FileInputStream(file), charset);
+    }
 }
diff --git a/ojluni/src/main/java/java/io/FileWriter.java b/ojluni/src/main/java/java/io/FileWriter.java
index 7475ea4..e49b316 100644
--- a/ojluni/src/main/java/java/io/FileWriter.java
+++ b/ojluni/src/main/java/java/io/FileWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, 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,34 +25,37 @@
 
 package java.io;
 
+import java.nio.charset.Charset;
 
 /**
- * Convenience class for writing character files.  The constructors of this
- * class assume that the default character encoding and the default byte-buffer
- * size are acceptable.  To specify these values yourself, construct an
- * OutputStreamWriter on a FileOutputStream.
+ * Writes text to character files using a default buffer size. Encoding from characters
+ * to bytes uses either a specified {@linkplain java.nio.charset.Charset charset}
+ * or the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
  *
- * <p>Whether or not a file is available or may be created depends upon the
+ * <p>
+ * Whether or not a file is available or may be created depends upon the
  * underlying platform.  Some platforms, in particular, allow a file to be
- * opened for writing by only one <tt>FileWriter</tt> (or other file-writing
+ * opened for writing by only one {@code FileWriter} (or other file-writing
  * object) at a time.  In such situations the constructors in this class
  * will fail if the file involved is already open.
  *
- * <p><code>FileWriter</code> is meant for writing streams of characters.
- * For writing streams of raw bytes, consider using a
- * <code>FileOutputStream</code>.
+ * <p>
+ * The {@code FileWriter} is meant for writing streams of characters. For writing
+ * streams of raw bytes, consider using a {@code FileOutputStream}.
  *
  * @see OutputStreamWriter
  * @see FileOutputStream
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class FileWriter extends OutputStreamWriter {
 
     /**
-     * Constructs a FileWriter object given a file name.
+     * Constructs a {@code FileWriter} given a file name, using the platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
      *
      * @param fileName  String The system-dependent filename.
      * @throws IOException  if the named file exists but is a directory rather
@@ -64,11 +67,12 @@
     }
 
     /**
-     * Constructs a FileWriter object given a file name with a boolean
-     * indicating whether or not to append the data written.
+     * Constructs a {@code FileWriter} given a file name and a boolean indicating
+     * whether to append the data written, using the platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
      *
      * @param fileName  String The system-dependent filename.
-     * @param append    boolean if <code>true</code>, then data will be written
+     * @param append    boolean if {@code true}, then data will be written
      *                  to the end of the file rather than the beginning.
      * @throws IOException  if the named file exists but is a directory rather
      *                  than a regular file, does not exist but cannot be
@@ -79,9 +83,11 @@
     }
 
     /**
-     * Constructs a FileWriter object given a File object.
+     * Constructs a {@code FileWriter} given the {@code File} to write,
+     * using the platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
      *
-     * @param file  a File object to write to.
+     * @param file  the {@code File} to write.
      * @throws IOException  if the file exists but is a directory rather than
      *                  a regular file, does not exist but cannot be created,
      *                  or cannot be opened for any other reason
@@ -91,12 +97,12 @@
     }
 
     /**
-     * Constructs a FileWriter object given a File object. If the second
-     * argument is <code>true</code>, then bytes will be written to the end
-     * of the file rather than the beginning.
+     * Constructs a {@code FileWriter} given the {@code File} to write and
+     * a boolean indicating whether to append the data written, using the platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
      *
-     * @param file  a File object to write to
-     * @param     append    if <code>true</code>, then bytes will be written
+     * @param file  the {@code File} to write
+     * @param     append    if {@code true}, then bytes will be written
      *                      to the end of the file rather than the beginning
      * @throws IOException  if the file exists but is a directory rather than
      *                  a regular file, does not exist but cannot be created,
@@ -108,12 +114,83 @@
     }
 
     /**
-     * Constructs a FileWriter object associated with a file descriptor.
+     * Constructs a {@code FileWriter} given a file descriptor,
+     * using the platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
      *
-     * @param fd  FileDescriptor object to write to.
+     * @param fd  the {@code FileDescriptor} to write.
      */
     public FileWriter(FileDescriptor fd) {
         super(new FileOutputStream(fd));
     }
 
+
+    /**
+     * Constructs a {@code FileWriter} given a file name and
+     * {@linkplain java.nio.charset.Charset charset}.
+     *
+     * @param fileName  the name of the file to write
+     * @param charset the {@linkplain java.nio.charset.Charset charset}
+     * @throws IOException  if the named file exists but is a directory rather
+     *                  than a regular file, does not exist but cannot be
+     *                  created, or cannot be opened for any other reason
+     *
+     * @since 11
+     */
+    public FileWriter(String fileName, Charset charset) throws IOException {
+        super(new FileOutputStream(fileName), charset);
+    }
+
+    /**
+     * Constructs a {@code FileWriter} given a file name,
+     * {@linkplain java.nio.charset.Charset charset} and a boolean indicating
+     * whether to append the data written.
+     *
+     * @param fileName  the name of the file to write
+     * @param charset the {@linkplain java.nio.charset.Charset charset}
+     * @param append    a boolean. If {@code true}, the writer will write the data
+     *                  to the end of the file rather than the beginning.
+     * @throws IOException  if the named file exists but is a directory rather
+     *                  than a regular file, does not exist but cannot be
+     *                  created, or cannot be opened for any other reason
+     *
+     * @since 11
+     */
+    public FileWriter(String fileName, Charset charset, boolean append) throws IOException {
+        super(new FileOutputStream(fileName, append), charset);
+    }
+
+    /**
+     * Constructs a {@code FileWriter} given the {@code File} to write and
+     * {@linkplain java.nio.charset.Charset charset}.
+     *
+     * @param file  the {@code File} to write
+     * @param charset the {@linkplain java.nio.charset.Charset charset}
+     * @throws IOException  if the file exists but is a directory rather than
+     *                  a regular file, does not exist but cannot be created,
+     *                  or cannot be opened for any other reason
+     *
+     * @since 11
+     */
+    public FileWriter(File file, Charset charset) throws IOException {
+        super(new FileOutputStream(file), charset);
+    }
+
+    /**
+     * Constructs a {@code FileWriter} given the {@code File} to write,
+     * {@linkplain java.nio.charset.Charset charset} and a boolean indicating
+     * whether to append the data written.
+     *
+     * @param file  the {@code File} to write
+     * @param charset the {@linkplain java.nio.charset.Charset charset}
+     * @param append    a boolean. If {@code true}, the writer will write the data
+     *                  to the end of the file rather than the beginning.
+     * @throws IOException  if the file exists but is a directory rather than
+     *                  a regular file, does not exist but cannot be created,
+     *                  or cannot be opened for any other reason
+     * @since 11
+     */
+    public FileWriter(File file, Charset charset, boolean append) throws IOException {
+        super(new FileOutputStream(file, append), charset);
+    }
 }
diff --git a/ojluni/src/main/java/java/io/PrintStream.java b/ojluni/src/main/java/java/io/PrintStream.java
index 809d39b..7df8353 100644
--- a/ojluni/src/main/java/java/io/PrintStream.java
+++ b/ojluni/src/main/java/java/io/PrintStream.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -33,26 +33,32 @@
 import java.nio.charset.UnsupportedCharsetException;
 
 /**
- * A <code>PrintStream</code> adds functionality to another output stream,
+ * A {@code PrintStream} adds functionality to another output stream,
  * namely the ability to print representations of various data values
  * conveniently.  Two other features are provided as well.  Unlike other output
- * streams, a <code>PrintStream</code> never throws an
- * <code>IOException</code>; instead, exceptional situations merely set an
- * internal flag that can be tested via the <code>checkError</code> method.
- * Optionally, a <code>PrintStream</code> can be created so as to flush
- * automatically; this means that the <code>flush</code> method is
+ * streams, a {@code PrintStream} never throws an
+ * {@code IOException}; instead, exceptional situations merely set an
+ * internal flag that can be tested via the {@code checkError} method.
+ * Optionally, a {@code PrintStream} can be created so as to flush
+ * automatically; this means that the {@code flush} method is
  * automatically invoked after a byte array is written, one of the
- * <code>println</code> methods is invoked, or a newline character or byte
- * (<code>'\n'</code>) is written.
+ * {@code println} methods is invoked, or a newline character or byte
+ * ({@code '\n'}) is written.
  *
- * <p> All characters printed by a <code>PrintStream</code> are converted into
- * bytes using the platform's default character encoding.  The <code>{@link
- * PrintWriter}</code> class should be used in situations that require writing
- * characters rather than bytes.
+ * <p> All characters printed by a {@code PrintStream} are converted into
+ * bytes using the given encoding or charset, or platform's default character
+ * encoding if not specified.
+ * The {@link PrintWriter} class should be used in situations that require
+ *  writing characters rather than bytes.
+ *
+ * <p> This class always replaces malformed and unmappable character sequences with
+ * the charset's default replacement string.
+ * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
+ * control over the encoding process is required.
  *
  * @author     Frank Yellin
  * @author     Mark Reinhold
- * @since      JDK1.0
+ * @since      1.0
  */
 
 public class PrintStream extends FilterOutputStream
@@ -110,24 +116,13 @@
         // this.textOut = new BufferedWriter(charOut);
     }
 
-    private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
-        super(out);
-        this.autoFlush = autoFlush;
-        // Android-changed: Lazy initialization of charOut and textOut.
-        // this.charOut = new OutputStreamWriter(this, charset);
-        // this.textOut = new BufferedWriter(charOut);
-        this.charset = charset;
-    }
-
     /* Variant of the private constructor so that the given charset name
      * can be verified before evaluating the OutputStream argument. Used
      * by constructors creating a FileOutputStream that also take a
      * charset name.
      */
-    private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
-        throws UnsupportedEncodingException
-    {
-        this(autoFlush, out, charset);
+    private PrintStream(boolean autoFlush, Charset charset, OutputStream out) {
+        this(out, autoFlush, charset);
     }
 
     /**
@@ -149,8 +144,8 @@
      *                    printed
      * @param  autoFlush  A boolean; if true, the output buffer will be flushed
      *                    whenever a byte array is written, one of the
-     *                    <code>println</code> methods is invoked, or a newline
-     *                    character or byte (<code>'\n'</code>) is written
+     *                    {@code println} methods is invoked, or a newline
+     *                    character or byte ({@code '\n'}) is written
      *
      * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
      */
@@ -165,8 +160,8 @@
      *                    printed
      * @param  autoFlush  A boolean; if true, the output buffer will be flushed
      *                    whenever a byte array is written, one of the
-     *                    <code>println</code> methods is invoked, or a newline
-     *                    character or byte (<code>'\n'</code>) is written
+     *                    {@code println} methods is invoked, or a newline
+     *                    character or byte ({@code '\n'}) is written
      * @param  encoding   The name of a supported
      *                    <a href="../lang/package-summary.html#charenc">
      *                    character encoding</a>
@@ -179,9 +174,30 @@
     public PrintStream(OutputStream out, boolean autoFlush, String encoding)
         throws UnsupportedEncodingException
     {
-        this(autoFlush,
-             requireNonNull(out, "Null output stream"),
-             toCharset(encoding));
+        this(requireNonNull(out, "Null output stream"), autoFlush, toCharset(encoding));
+    }
+
+    /**
+     * Creates a new print stream, with the specified OutputStream, automatic line
+     * flushing and charset.  This convenience constructor creates the necessary
+     * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
+     * which will encode characters using the provided charset.
+     *
+     * @param  out        The output stream to which values and objects will be
+     *                    printed
+     * @param  autoFlush  A boolean; if true, the output buffer will be flushed
+     *                    whenever a byte array is written, one of the
+     *                    {@code println} methods is invoked, or a newline
+     *                    character or byte ({@code '\n'}) is written
+     * @param  charset    A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @since  10
+     */
+    public PrintStream(OutputStream out, boolean autoFlush, Charset charset) {
+        super(out);
+        this.autoFlush = autoFlush;
+        this.charOut = new OutputStreamWriter(this, charset);
+        this.textOut = new BufferedWriter(charOut);
     }
 
     /**
@@ -257,6 +273,36 @@
 
     /**
      * Creates a new print stream, without automatic line flushing, with the
+     * specified file name and charset.  This convenience constructor creates
+     * the necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the provided
+     * charset.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this print
+     *         stream.  If the file exists, then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  charset
+     *         A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @throws  IOException
+     *          if an I/O error occurs while opening or creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @since  10
+     */
+    public PrintStream(String fileName, Charset charset) throws IOException {
+        this(false, requireNonNull(charset, "charset"), new FileOutputStream(fileName));
+    }
+
+    /**
+     * Creates a new print stream, without automatic line flushing, with the
      * specified file.  This convenience constructor creates the necessary
      * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
      * which will encode characters using the {@linkplain
@@ -326,6 +372,37 @@
         this(false, toCharset(csn), new FileOutputStream(file));
     }
 
+
+    /**
+     * Creates a new print stream, without automatic line flushing, with the
+     * specified file and charset.  This convenience constructor creates
+     * the necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the provided
+     * charset.
+     *
+     * @param  file
+     *         The file to use as the destination of this print stream.  If the
+     *         file exists, then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  charset
+     *         A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @throws  IOException
+     *          if an I/O error occurs while opening or creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())}
+     *          denies write access to the file
+     *
+     * @since  10
+     */
+    public PrintStream(File file, Charset charset) throws IOException {
+        this(false, requireNonNull(charset, "charset"), new FileOutputStream(file));
+    }
+
     /** Check to make sure that the stream has not been closed */
     private void ensureOpen() throws IOException {
         if (out == null)
@@ -394,21 +471,21 @@
 
     /**
      * Flushes the stream and checks its error state. The internal error state
-     * is set to <code>true</code> when the underlying output stream throws an
-     * <code>IOException</code> other than <code>InterruptedIOException</code>,
-     * and when the <code>setError</code> method is invoked.  If an operation
+     * is set to {@code true} when the underlying output stream throws an
+     * {@code IOException} other than {@code InterruptedIOException},
+     * and when the {@code setError} method is invoked.  If an operation
      * on the underlying output stream throws an
-     * <code>InterruptedIOException</code>, then the <code>PrintStream</code>
+     * {@code InterruptedIOException}, then the {@code PrintStream}
      * converts the exception back into an interrupt by doing:
-     * <pre>
+     * <pre>{@code
      *     Thread.currentThread().interrupt();
-     * </pre>
+     * }</pre>
      * or the equivalent.
      *
-     * @return <code>true</code> if and only if this stream has encountered an
-     *         <code>IOException</code> other than
-     *         <code>InterruptedIOException</code>, or the
-     *         <code>setError</code> method has been invoked
+     * @return {@code true} if and only if this stream has encountered an
+     *         {@code IOException} other than
+     *         {@code InterruptedIOException}, or the
+     *         {@code setError} method has been invoked
      */
     public boolean checkError() {
         if (out != null)
@@ -421,13 +498,13 @@
     }
 
     /**
-     * Sets the error state of the stream to <code>true</code>.
+     * Sets the error state of the stream to {@code true}.
      *
      * <p> This method will cause subsequent invocations of {@link
-     * #checkError()} to return <tt>true</tt> until {@link
-     * #clearError()} is invoked.
+     * #checkError()} to return {@code true} until
+     * {@link #clearError()} is invoked.
      *
-     * @since JDK1.1
+     * @since 1.1
      */
     protected void setError() {
         trouble = true;
@@ -437,7 +514,7 @@
      * Clears the internal error state of this stream.
      *
      * <p> This method will cause subsequent invocations of {@link
-     * #checkError()} to return <tt>false</tt> until another write
+     * #checkError()} to return {@code false} until another write
      * operation fails and invokes {@link #setError()}.
      *
      * @since 1.6
@@ -453,12 +530,12 @@
 
     /**
      * Writes the specified byte to this stream.  If the byte is a newline and
-     * automatic flushing is enabled then the <code>flush</code> method will be
+     * automatic flushing is enabled then the {@code flush} method will be
      * invoked.
      *
      * <p> Note that the byte is written as given; to write a character that
      * will be translated according to the platform's default character
-     * encoding, use the <code>print(char)</code> or <code>println(char)</code>
+     * encoding, use the {@code print(char)} or {@code println(char)}
      * methods.
      *
      * @param  b  The byte to be written
@@ -483,13 +560,13 @@
     }
 
     /**
-     * Writes <code>len</code> bytes from the specified byte array starting at
-     * offset <code>off</code> to this stream.  If automatic flushing is
-     * enabled then the <code>flush</code> method will be invoked.
+     * Writes {@code len} bytes from the specified byte array starting at
+     * offset {@code off} to this stream.  If automatic flushing is
+     * enabled then the {@code flush} method will be invoked.
      *
      * <p> Note that the bytes will be written as given; to write characters
      * that will be translated according to the platform's default character
-     * encoding, use the <code>print(char)</code> or <code>println(char)</code>
+     * encoding, use the {@code print(char)} or {@code println(char)}
      * methods.
      *
      * @param  buf   A byte array
@@ -588,38 +665,38 @@
     /* Methods that do not terminate lines */
 
     /**
-     * Prints a boolean value.  The string produced by <code>{@link
-     * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+     * Prints a boolean value.  The string produced by {@link
+     * java.lang.String#valueOf(boolean)} is translated into bytes
      * according to the platform's default character encoding, and these bytes
      * are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
-     * @param      b   The <code>boolean</code> to be printed
+     * @param      b   The {@code boolean} to be printed
      */
     public void print(boolean b) {
-        write(b ? "true" : "false");
+        write(String.valueOf(b));
     }
 
     /**
      * Prints a character.  The character is translated into one or more bytes
      * according to the platform's default character encoding, and these bytes
      * are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
-     * @param      c   The <code>char</code> to be printed
+     * @param      c   The {@code char} to be printed
      */
     public void print(char c) {
         write(String.valueOf(c));
     }
 
     /**
-     * Prints an integer.  The string produced by <code>{@link
-     * java.lang.String#valueOf(int)}</code> is translated into bytes
+     * Prints an integer.  The string produced by {@link
+     * java.lang.String#valueOf(int)} is translated into bytes
      * according to the platform's default character encoding, and these bytes
      * are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
-     * @param      i   The <code>int</code> to be printed
+     * @param      i   The {@code int} to be printed
      * @see        java.lang.Integer#toString(int)
      */
     public void print(int i) {
@@ -627,13 +704,13 @@
     }
 
     /**
-     * Prints a long integer.  The string produced by <code>{@link
-     * java.lang.String#valueOf(long)}</code> is translated into bytes
+     * Prints a long integer.  The string produced by {@link
+     * java.lang.String#valueOf(long)} is translated into bytes
      * according to the platform's default character encoding, and these bytes
      * are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
-     * @param      l   The <code>long</code> to be printed
+     * @param      l   The {@code long} to be printed
      * @see        java.lang.Long#toString(long)
      */
     public void print(long l) {
@@ -641,13 +718,13 @@
     }
 
     /**
-     * Prints a floating-point number.  The string produced by <code>{@link
-     * java.lang.String#valueOf(float)}</code> is translated into bytes
+     * Prints a floating-point number.  The string produced by {@link
+     * java.lang.String#valueOf(float)} is translated into bytes
      * according to the platform's default character encoding, and these bytes
      * are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
-     * @param      f   The <code>float</code> to be printed
+     * @param      f   The {@code float} to be printed
      * @see        java.lang.Float#toString(float)
      */
     public void print(float f) {
@@ -656,12 +733,12 @@
 
     /**
      * Prints a double-precision floating-point number.  The string produced by
-     * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+     * {@link java.lang.String#valueOf(double)} is translated into
      * bytes according to the platform's default character encoding, and these
-     * bytes are written in exactly the manner of the <code>{@link
-     * #write(int)}</code> method.
+     * bytes are written in exactly the manner of the {@link
+     * #write(int)} method.
      *
-     * @param      d   The <code>double</code> to be printed
+     * @param      d   The {@code double} to be printed
      * @see        java.lang.Double#toString(double)
      */
     public void print(double d) {
@@ -672,40 +749,37 @@
      * Prints an array of characters.  The characters are converted into bytes
      * according to the platform's default character encoding, and these bytes
      * are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
      * @param      s   The array of chars to be printed
      *
-     * @throws  NullPointerException  If <code>s</code> is <code>null</code>
+     * @throws  NullPointerException  If {@code s} is {@code null}
      */
     public void print(char s[]) {
         write(s);
     }
 
     /**
-     * Prints a string.  If the argument is <code>null</code> then the string
-     * <code>"null"</code> is printed.  Otherwise, the string's characters are
+     * Prints a string.  If the argument is {@code null} then the string
+     * {@code "null"} is printed.  Otherwise, the string's characters are
      * converted into bytes according to the platform's default character
      * encoding, and these bytes are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
-     * @param      s   The <code>String</code> to be printed
+     * @param      s   The {@code String} to be printed
      */
     public void print(String s) {
-        if (s == null) {
-            s = "null";
-        }
-        write(s);
+        write(String.valueOf(s));
     }
 
     /**
-     * Prints an object.  The string produced by the <code>{@link
-     * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+     * Prints an object.  The string produced by the {@link
+     * java.lang.String#valueOf(Object)} method is translated into bytes
      * according to the platform's default character encoding, and these bytes
      * are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
-     * @param      obj   The <code>Object</code> to be printed
+     * @param      obj   The {@code Object} to be printed
      * @see        java.lang.Object#toString()
      */
     public void print(Object obj) {
@@ -718,8 +792,8 @@
     /**
      * Terminates the current line by writing the line separator string.  The
      * line separator string is defined by the system property
-     * <code>line.separator</code>, and is not necessarily a single newline
-     * character (<code>'\n'</code>).
+     * {@code line.separator}, and is not necessarily a single newline
+     * character ({@code '\n'}).
      */
     public void println() {
         newLine();
@@ -727,10 +801,10 @@
 
     /**
      * Prints a boolean and then terminate the line.  This method behaves as
-     * though it invokes <code>{@link #print(boolean)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(boolean)} and then
+     * {@link #println()}.
      *
-     * @param x  The <code>boolean</code> to be printed
+     * @param x  The {@code boolean} to be printed
      */
     public void println(boolean x) {
         synchronized (this) {
@@ -741,10 +815,10 @@
 
     /**
      * Prints a character and then terminate the line.  This method behaves as
-     * though it invokes <code>{@link #print(char)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(char)} and then
+     * {@link #println()}.
      *
-     * @param x  The <code>char</code> to be printed.
+     * @param x  The {@code char} to be printed.
      */
     public void println(char x) {
         synchronized (this) {
@@ -755,10 +829,10 @@
 
     /**
      * Prints an integer and then terminate the line.  This method behaves as
-     * though it invokes <code>{@link #print(int)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(int)} and then
+     * {@link #println()}.
      *
-     * @param x  The <code>int</code> to be printed.
+     * @param x  The {@code int} to be printed.
      */
     public void println(int x) {
         synchronized (this) {
@@ -769,10 +843,10 @@
 
     /**
      * Prints a long and then terminate the line.  This method behaves as
-     * though it invokes <code>{@link #print(long)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(long)} and then
+     * {@link #println()}.
      *
-     * @param x  a The <code>long</code> to be printed.
+     * @param x  a The {@code long} to be printed.
      */
     public void println(long x) {
         synchronized (this) {
@@ -783,10 +857,10 @@
 
     /**
      * Prints a float and then terminate the line.  This method behaves as
-     * though it invokes <code>{@link #print(float)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(float)} and then
+     * {@link #println()}.
      *
-     * @param x  The <code>float</code> to be printed.
+     * @param x  The {@code float} to be printed.
      */
     public void println(float x) {
         synchronized (this) {
@@ -797,10 +871,10 @@
 
     /**
      * Prints a double and then terminate the line.  This method behaves as
-     * though it invokes <code>{@link #print(double)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(double)} and then
+     * {@link #println()}.
      *
-     * @param x  The <code>double</code> to be printed.
+     * @param x  The {@code double} to be printed.
      */
     public void println(double x) {
         synchronized (this) {
@@ -811,8 +885,8 @@
 
     /**
      * Prints an array of characters and then terminate the line.  This method
-     * behaves as though it invokes <code>{@link #print(char[])}</code> and
-     * then <code>{@link #println()}</code>.
+     * behaves as though it invokes {@link #print(char[])} and
+     * then {@link #println()}.
      *
      * @param x  an array of chars to print.
      */
@@ -825,10 +899,10 @@
 
     /**
      * Prints a String and then terminate the line.  This method behaves as
-     * though it invokes <code>{@link #print(String)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(String)} and then
+     * {@link #println()}.
      *
-     * @param x  The <code>String</code> to be printed.
+     * @param x  The {@code String} to be printed.
      */
     public void println(String x) {
         synchronized (this) {
@@ -841,10 +915,10 @@
      * Prints an Object and then terminate the line.  This method calls
      * at first String.valueOf(x) to get the printed object's string value,
      * then behaves as
-     * though it invokes <code>{@link #print(String)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(String)} and then
+     * {@link #println()}.
      *
-     * @param x  The <code>Object</code> to be printed.
+     * @param x  The {@code Object} to be printed.
      */
     public void println(Object x) {
         String s = String.valueOf(x);
@@ -859,11 +933,13 @@
      * A convenience method to write a formatted string to this output stream
      * using the specified format string and arguments.
      *
-     * <p> An invocation of this method of the form <tt>out.printf(format,
-     * args)</tt> behaves in exactly the same way as the invocation
+     * <p> An invocation of this method of the form
+     * {@code out.printf(format, args)} behaves
+     * in exactly the same way as the invocation
      *
-     * <pre>
-     *     out.format(format, args) </pre>
+     * <pre>{@code
+     *     out.format(format, args)
+     * }</pre>
      *
      * @param  format
      *         A format string as described in <a
@@ -877,7 +953,7 @@
      *         limited by the maximum dimension of a Java array as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *         The behaviour on a
-     *         <tt>null</tt> argument depends on the <a
+     *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
      * @throws  java.util.IllegalFormatException
@@ -890,7 +966,7 @@
      *          formatter class specification.
      *
      * @throws  NullPointerException
-     *          If the <tt>format</tt> is <tt>null</tt>
+     *          If the {@code format} is {@code null}
      *
      * @return  This output stream
      *
@@ -904,15 +980,17 @@
      * A convenience method to write a formatted string to this output stream
      * using the specified format string and arguments.
      *
-     * <p> An invocation of this method of the form <tt>out.printf(l, format,
-     * args)</tt> behaves in exactly the same way as the invocation
+     * <p> An invocation of this method of the form
+     * {@code out.printf(l, format, args)} behaves
+     * in exactly the same way as the invocation
      *
-     * <pre>
-     *     out.format(l, format, args) </pre>
+     * <pre>{@code
+     *     out.format(l, format, args)
+     * }</pre>
      *
      * @param  l
      *         The {@linkplain java.util.Locale locale} to apply during
-     *         formatting.  If <tt>l</tt> is <tt>null</tt> then no localization
+     *         formatting.  If {@code l} is {@code null} then no localization
      *         is applied.
      *
      * @param  format
@@ -927,7 +1005,7 @@
      *         limited by the maximum dimension of a Java array as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *         The behaviour on a
-     *         <tt>null</tt> argument depends on the <a
+     *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
      * @throws  java.util.IllegalFormatException
@@ -940,7 +1018,7 @@
      *          formatter class specification.
      *
      * @throws  NullPointerException
-     *          If the <tt>format</tt> is <tt>null</tt>
+     *          If the {@code format} is {@code null}
      *
      * @return  This output stream
      *
@@ -955,8 +1033,10 @@
      * format string and arguments.
      *
      * <p> The locale always used is the one returned by {@link
-     * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
-     * previous invocations of other formatting methods on this object.
+     * java.util.Locale#getDefault(Locale.Category)} with
+     * {@link java.util.Locale.Category#FORMAT FORMAT} category specified,
+     * regardless of any previous invocations of other formatting methods on
+     * this object.
      *
      * @param  format
      *         A format string as described in <a
@@ -970,7 +1050,7 @@
      *         limited by the maximum dimension of a Java array as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *         The behaviour on a
-     *         <tt>null</tt> argument depends on the <a
+     *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
      * @throws  java.util.IllegalFormatException
@@ -983,7 +1063,7 @@
      *          formatter class specification.
      *
      * @throws  NullPointerException
-     *          If the <tt>format</tt> is <tt>null</tt>
+     *          If the {@code format} is {@code null}
      *
      * @return  This output stream
      *
@@ -994,9 +1074,11 @@
             synchronized (this) {
                 ensureOpen();
                 if ((formatter == null)
-                    || (formatter.locale() != Locale.getDefault()))
+                    || (formatter.locale() !=
+                        Locale.getDefault(Locale.Category.FORMAT)))
                     formatter = new Formatter((Appendable) this);
-                formatter.format(Locale.getDefault(), format, args);
+                formatter.format(Locale.getDefault(Locale.Category.FORMAT),
+                                 format, args);
             }
         } catch (InterruptedIOException x) {
             Thread.currentThread().interrupt();
@@ -1012,7 +1094,7 @@
      *
      * @param  l
      *         The {@linkplain java.util.Locale locale} to apply during
-     *         formatting.  If <tt>l</tt> is <tt>null</tt> then no localization
+     *         formatting.  If {@code l} is {@code null} then no localization
      *         is applied.
      *
      * @param  format
@@ -1027,7 +1109,7 @@
      *         limited by the maximum dimension of a Java array as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *         The behaviour on a
-     *         <tt>null</tt> argument depends on the <a
+     *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
      * @throws  java.util.IllegalFormatException
@@ -1040,7 +1122,7 @@
      *          formatter class specification.
      *
      * @throws  NullPointerException
-     *          If the <tt>format</tt> is <tt>null</tt>
+     *          If the {@code format} is {@code null}
      *
      * @return  This output stream
      *
@@ -1066,21 +1148,22 @@
     /**
      * Appends the specified character sequence to this output stream.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * <p> An invocation of this method of the form {@code out.append(csq)}
      * behaves in exactly the same way as the invocation
      *
-     * <pre>
-     *     out.print(csq.toString()) </pre>
+     * <pre>{@code
+     *     out.print(csq.toString())
+     * }</pre>
      *
-     * <p> Depending on the specification of <tt>toString</tt> for the
-     * character sequence <tt>csq</tt>, the entire sequence may not be
-     * appended.  For instance, invoking then <tt>toString</tt> method of a
+     * <p> Depending on the specification of {@code toString} for the
+     * character sequence {@code csq}, the entire sequence may not be
+     * appended.  For instance, invoking then {@code toString} method of a
      * character buffer will return a subsequence whose content depends upon
      * the buffer's position and limit.
      *
      * @param  csq
-     *         The character sequence to append.  If <tt>csq</tt> is
-     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         The character sequence to append.  If {@code csq} is
+     *         {@code null}, then the four characters {@code "null"} are
      *         appended to this output stream.
      *
      * @return  This output stream
@@ -1088,10 +1171,7 @@
      * @since  1.5
      */
     public PrintStream append(CharSequence csq) {
-        if (csq == null)
-            print("null");
-        else
-            print(csq.toString());
+        print(String.valueOf(csq));
         return this;
     }
 
@@ -1099,18 +1179,20 @@
      * Appends a subsequence of the specified character sequence to this output
      * stream.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq, start,
-     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * <p> An invocation of this method of the form
+     * {@code out.append(csq, start, end)} when
+     * {@code csq} is not {@code null}, behaves in
      * exactly the same way as the invocation
      *
-     * <pre>
-     *     out.print(csq.subSequence(start, end).toString()) </pre>
+     * <pre>{@code
+     *     out.print(csq.subSequence(start, end).toString())
+     * }</pre>
      *
      * @param  csq
      *         The character sequence from which a subsequence will be
-     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
-     *         will be appended as if <tt>csq</tt> contained the four
-     *         characters <tt>"null"</tt>.
+     *         appended.  If {@code csq} is {@code null}, then characters
+     *         will be appended as if {@code csq} contained the four
+     *         characters {@code "null"}.
      *
      * @param  start
      *         The index of the first character in the subsequence
@@ -1122,26 +1204,26 @@
      * @return  This output stream
      *
      * @throws  IndexOutOfBoundsException
-     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
-     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
-     *          <tt>csq.length()</tt>
+     *          If {@code start} or {@code end} are negative, {@code start}
+     *          is greater than {@code end}, or {@code end} is greater than
+     *          {@code csq.length()}
      *
      * @since  1.5
      */
     public PrintStream append(CharSequence csq, int start, int end) {
-        CharSequence cs = (csq == null ? "null" : csq);
-        write(cs.subSequence(start, end).toString());
-        return this;
+        if (csq == null) csq = "null";
+        return append(csq.subSequence(start, end));
     }
 
     /**
      * Appends the specified character to this output stream.
      *
-     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * <p> An invocation of this method of the form {@code out.append(c)}
      * behaves in exactly the same way as the invocation
      *
-     * <pre>
-     *     out.print(c) </pre>
+     * <pre>{@code
+     *     out.print(c)
+     * }</pre>
      *
      * @param  c
      *         The 16-bit character to append
diff --git a/ojluni/src/main/java/java/io/PrintWriter.java b/ojluni/src/main/java/java/io/PrintWriter.java
index 9287a19..37d4200 100644
--- a/ojluni/src/main/java/java/io/PrintWriter.java
+++ b/ojluni/src/main/java/java/io/PrintWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -34,13 +34,13 @@
 
 /**
  * Prints formatted representations of objects to a text-output stream.  This
- * class implements all of the <tt>print</tt> methods found in {@link
+ * class implements all of the {@code print} methods found in {@link
  * PrintStream}.  It does not contain methods for writing raw bytes, for which
  * a program should use unencoded byte streams.
  *
  * <p> Unlike the {@link PrintStream} class, if automatic flushing is enabled
- * it will be done only when one of the <tt>println</tt>, <tt>printf</tt>, or
- * <tt>format</tt> methods is invoked, rather than whenever a newline character
+ * it will be done only when one of the {@code println}, {@code printf}, or
+ * {@code format} methods is invoked, rather than whenever a newline character
  * happens to be output.  These methods use the platform's own notion of line
  * separator rather than the newline character.
  *
@@ -48,16 +48,21 @@
  * constructors may.  The client may inquire as to whether any errors have
  * occurred by invoking {@link #checkError checkError()}.
  *
+ * <p> This class always replaces malformed and unmappable character sequences with
+ * the charset's default replacement string.
+ * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
+ * control over the encoding process is required.
+ *
  * @author      Frank Yellin
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public class PrintWriter extends Writer {
 
     /**
      * The underlying character-output stream of this
-     * <code>PrintWriter</code>.
+     * {@code PrintWriter}.
      *
      * @since 1.2
      */
@@ -69,12 +74,6 @@
     private PrintStream psOut = null;
 
     /**
-     * Line separator string.  This is the value of the line.separator
-     * property at the moment that the stream was created.
-     */
-    private final String lineSeparator;
-
-    /**
      * Returns a charset object for the given charset name.
      * @throws NullPointerException          is csn is null
      * @throws UnsupportedEncodingException  if the charset is not supported
@@ -113,8 +112,6 @@
         super(out);
         this.out = out;
         this.autoFlush = autoFlush;
-        lineSeparator = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("line.separator"));
     }
 
     /**
@@ -138,14 +135,33 @@
      * default character encoding.
      *
      * @param  out        An output stream
-     * @param  autoFlush  A boolean; if true, the <tt>println</tt>,
-     *                    <tt>printf</tt>, or <tt>format</tt> methods will
+     * @param  autoFlush  A boolean; if true, the {@code println},
+     *                    {@code printf}, or {@code format} methods will
      *                    flush the output buffer
      *
      * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
      */
     public PrintWriter(OutputStream out, boolean autoFlush) {
-        this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
+        this(out, autoFlush, Charset.defaultCharset());
+    }
+
+    /**
+     * Creates a new PrintWriter from an existing OutputStream.  This
+     * convenience constructor creates the necessary intermediate
+     * OutputStreamWriter, which will convert characters into bytes using the
+     * specified charset.
+     *
+     * @param  out        An output stream
+     * @param  autoFlush  A boolean; if true, the {@code println},
+     *                    {@code printf}, or {@code format} methods will
+     *                    flush the output buffer
+     * @param  charset
+     *         A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @since 10
+     */
+    public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) {
+        this(new BufferedWriter(new OutputStreamWriter(out, charset)), autoFlush);
 
         // save print stream for error propagation
         if (out instanceof java.io.PrintStream) {
@@ -234,6 +250,36 @@
 
     /**
      * Creates a new PrintWriter, without automatic line flushing, with the
+     * specified file name and charset.  This convenience constructor creates
+     * the necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the provided
+     * charset.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this writer.
+     *         If the file exists then it will be truncated to zero size;
+     *         otherwise, a new file will be created.  The output will be
+     *         written to the file and is buffered.
+     *
+     * @param  charset
+     *         A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @throws  IOException
+     *          if an I/O error occurs while opening or creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @since  10
+     */
+    public PrintWriter(String fileName, Charset charset) throws IOException {
+        this(Objects.requireNonNull(charset, "charset"), new File(fileName));
+    }
+
+    /**
+     * Creates a new PrintWriter, without automatic line flushing, with the
      * specified file.  This convenience constructor creates the necessary
      * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
      * which will encode characters using the {@linkplain
@@ -303,6 +349,36 @@
         this(toCharset(csn), file);
     }
 
+    /**
+     * Creates a new PrintWriter, without automatic line flushing, with the
+     * specified file and charset.  This convenience constructor creates the
+     * necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the provided
+     * charset.
+     *
+     * @param  file
+     *         The file to use as the destination of this writer.  If the file
+     *         exists then it will be truncated to zero size; otherwise, a new
+     *         file will be created.  The output will be written to the file
+     *         and is buffered.
+     *
+     * @param  charset
+     *         A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @throws  IOException
+     *          if an I/O error occurs while opening or creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())}
+     *          denies write access to the file
+     *
+     * @since  10
+     */
+    public PrintWriter(File file, Charset charset) throws IOException {
+        this(Objects.requireNonNull(charset, "charset"), file);
+    }
+
     /** Checks to make sure that the stream has not been closed */
     private void ensureOpen() throws IOException {
         if (out == null)
@@ -348,7 +424,7 @@
     /**
      * Flushes the stream if it's not closed and checks its error state.
      *
-     * @return <code>true</code> if the print stream has encountered an error,
+     * @return {@code true} if the print stream has encountered an error,
      *          either on the underlying output stream or during a format
      *          conversion.
      */
@@ -369,7 +445,7 @@
      * Indicates that an error has occurred.
      *
      * <p> This method will cause subsequent invocations of {@link
-     * #checkError()} to return <tt>true</tt> until {@link
+     * #checkError()} to return {@code true} until {@link
      * #clearError()} is invoked.
      */
     protected void setError() {
@@ -380,7 +456,7 @@
      * Clears the error state of this stream.
      *
      * <p> This method will cause subsequent invocations of {@link
-     * #checkError()} to return <tt>false</tt> until another write
+     * #checkError()} to return {@code false} until another write
      * operation fails and invokes {@link #setError()}.
      *
      * @since 1.6
@@ -418,6 +494,11 @@
      * @param buf Array of characters
      * @param off Offset from which to start writing characters
      * @param len Number of characters to write
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the values of the {@code off} and {@code len} parameters
+     *          cause the corresponding method of the underlying {@code Writer}
+     *          to throw an {@code IndexOutOfBoundsException}
      */
     public void write(char buf[], int off, int len) {
         try {
@@ -448,6 +529,11 @@
      * @param s A String
      * @param off Offset from which to start writing characters
      * @param len Number of characters to write
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the values of the {@code off} and {@code len} parameters
+     *          cause the corresponding method of the underlying {@code Writer}
+     *          to throw an {@code IndexOutOfBoundsException}
      */
     public void write(String s, int off, int len) {
         try {
@@ -477,7 +563,7 @@
         try {
             synchronized (lock) {
                 ensureOpen();
-                out.write(lineSeparator);
+                out.write(System.lineSeparator());
                 if (autoFlush)
                     out.flush();
             }
@@ -493,38 +579,38 @@
     /* Methods that do not terminate lines */
 
     /**
-     * Prints a boolean value.  The string produced by <code>{@link
-     * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+     * Prints a boolean value.  The string produced by {@link
+     * java.lang.String#valueOf(boolean)} is translated into bytes
      * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link
-     * #write(int)}</code> method.
+     * are written in exactly the manner of the {@link
+     * #write(int)} method.
      *
-     * @param      b   The <code>boolean</code> to be printed
+     * @param      b   The {@code boolean} to be printed
      */
     public void print(boolean b) {
-        write(b ? "true" : "false");
+        write(String.valueOf(b));
     }
 
     /**
      * Prints a character.  The character is translated into one or more bytes
      * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link
-     * #write(int)}</code> method.
+     * are written in exactly the manner of the {@link
+     * #write(int)} method.
      *
-     * @param      c   The <code>char</code> to be printed
+     * @param      c   The {@code char} to be printed
      */
     public void print(char c) {
         write(c);
     }
 
     /**
-     * Prints an integer.  The string produced by <code>{@link
-     * java.lang.String#valueOf(int)}</code> is translated into bytes according
+     * Prints an integer.  The string produced by {@link
+     * java.lang.String#valueOf(int)} is translated into bytes according
      * to the platform's default character encoding, and these bytes are
-     * written in exactly the manner of the <code>{@link #write(int)}</code>
+     * written in exactly the manner of the {@link #write(int)}
      * method.
      *
-     * @param      i   The <code>int</code> to be printed
+     * @param      i   The {@code int} to be printed
      * @see        java.lang.Integer#toString(int)
      */
     public void print(int i) {
@@ -532,13 +618,13 @@
     }
 
     /**
-     * Prints a long integer.  The string produced by <code>{@link
-     * java.lang.String#valueOf(long)}</code> is translated into bytes
+     * Prints a long integer.  The string produced by {@link
+     * java.lang.String#valueOf(long)} is translated into bytes
      * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * are written in exactly the manner of the {@link #write(int)}
      * method.
      *
-     * @param      l   The <code>long</code> to be printed
+     * @param      l   The {@code long} to be printed
      * @see        java.lang.Long#toString(long)
      */
     public void print(long l) {
@@ -546,13 +632,13 @@
     }
 
     /**
-     * Prints a floating-point number.  The string produced by <code>{@link
-     * java.lang.String#valueOf(float)}</code> is translated into bytes
+     * Prints a floating-point number.  The string produced by {@link
+     * java.lang.String#valueOf(float)} is translated into bytes
      * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * are written in exactly the manner of the {@link #write(int)}
      * method.
      *
-     * @param      f   The <code>float</code> to be printed
+     * @param      f   The {@code float} to be printed
      * @see        java.lang.Float#toString(float)
      */
     public void print(float f) {
@@ -561,12 +647,12 @@
 
     /**
      * Prints a double-precision floating-point number.  The string produced by
-     * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+     * {@link java.lang.String#valueOf(double)} is translated into
      * bytes according to the platform's default character encoding, and these
-     * bytes are written in exactly the manner of the <code>{@link
-     * #write(int)}</code> method.
+     * bytes are written in exactly the manner of the {@link
+     * #write(int)} method.
      *
-     * @param      d   The <code>double</code> to be printed
+     * @param      d   The {@code double} to be printed
      * @see        java.lang.Double#toString(double)
      */
     public void print(double d) {
@@ -576,41 +662,38 @@
     /**
      * Prints an array of characters.  The characters are converted into bytes
      * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * are written in exactly the manner of the {@link #write(int)}
      * method.
      *
      * @param      s   The array of chars to be printed
      *
-     * @throws  NullPointerException  If <code>s</code> is <code>null</code>
+     * @throws  NullPointerException  If {@code s} is {@code null}
      */
     public void print(char s[]) {
         write(s);
     }
 
     /**
-     * Prints a string.  If the argument is <code>null</code> then the string
-     * <code>"null"</code> is printed.  Otherwise, the string's characters are
+     * Prints a string.  If the argument is {@code null} then the string
+     * {@code "null"} is printed.  Otherwise, the string's characters are
      * converted into bytes according to the platform's default character
      * encoding, and these bytes are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
+     * {@link #write(int)} method.
      *
-     * @param      s   The <code>String</code> to be printed
+     * @param      s   The {@code String} to be printed
      */
     public void print(String s) {
-        if (s == null) {
-            s = "null";
-        }
-        write(s);
+        write(String.valueOf(s));
     }
 
     /**
-     * Prints an object.  The string produced by the <code>{@link
-     * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+     * Prints an object.  The string produced by the {@link
+     * java.lang.String#valueOf(Object)} method is translated into bytes
      * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * are written in exactly the manner of the {@link #write(int)}
      * method.
      *
-     * @param      obj   The <code>Object</code> to be printed
+     * @param      obj   The {@code Object} to be printed
      * @see        java.lang.Object#toString()
      */
     public void print(Object obj) {
@@ -622,8 +705,8 @@
     /**
      * Terminates the current line by writing the line separator string.  The
      * line separator string is defined by the system property
-     * <code>line.separator</code>, and is not necessarily a single newline
-     * character (<code>'\n'</code>).
+     * {@code line.separator}, and is not necessarily a single newline
+     * character ({@code '\n'}).
      */
     public void println() {
         newLine();
@@ -631,10 +714,10 @@
 
     /**
      * Prints a boolean value and then terminates the line.  This method behaves
-     * as though it invokes <code>{@link #print(boolean)}</code> and then
-     * <code>{@link #println()}</code>.
+     * as though it invokes {@link #print(boolean)} and then
+     * {@link #println()}.
      *
-     * @param x the <code>boolean</code> value to be printed
+     * @param x the {@code boolean} value to be printed
      */
     public void println(boolean x) {
         synchronized (lock) {
@@ -645,10 +728,10 @@
 
     /**
      * Prints a character and then terminates the line.  This method behaves as
-     * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
-     * #println()}</code>.
+     * though it invokes {@link #print(char)} and then {@link
+     * #println()}.
      *
-     * @param x the <code>char</code> value to be printed
+     * @param x the {@code char} value to be printed
      */
     public void println(char x) {
         synchronized (lock) {
@@ -659,10 +742,10 @@
 
     /**
      * Prints an integer and then terminates the line.  This method behaves as
-     * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
-     * #println()}</code>.
+     * though it invokes {@link #print(int)} and then {@link
+     * #println()}.
      *
-     * @param x the <code>int</code> value to be printed
+     * @param x the {@code int} value to be printed
      */
     public void println(int x) {
         synchronized (lock) {
@@ -673,10 +756,10 @@
 
     /**
      * Prints a long integer and then terminates the line.  This method behaves
-     * as though it invokes <code>{@link #print(long)}</code> and then
-     * <code>{@link #println()}</code>.
+     * as though it invokes {@link #print(long)} and then
+     * {@link #println()}.
      *
-     * @param x the <code>long</code> value to be printed
+     * @param x the {@code long} value to be printed
      */
     public void println(long x) {
         synchronized (lock) {
@@ -687,10 +770,10 @@
 
     /**
      * Prints a floating-point number and then terminates the line.  This method
-     * behaves as though it invokes <code>{@link #print(float)}</code> and then
-     * <code>{@link #println()}</code>.
+     * behaves as though it invokes {@link #print(float)} and then
+     * {@link #println()}.
      *
-     * @param x the <code>float</code> value to be printed
+     * @param x the {@code float} value to be printed
      */
     public void println(float x) {
         synchronized (lock) {
@@ -701,10 +784,10 @@
 
     /**
      * Prints a double-precision floating-point number and then terminates the
-     * line.  This method behaves as though it invokes <code>{@link
-     * #print(double)}</code> and then <code>{@link #println()}</code>.
+     * line.  This method behaves as though it invokes {@link
+     * #print(double)} and then {@link #println()}.
      *
-     * @param x the <code>double</code> value to be printed
+     * @param x the {@code double} value to be printed
      */
     public void println(double x) {
         synchronized (lock) {
@@ -715,10 +798,10 @@
 
     /**
      * Prints an array of characters and then terminates the line.  This method
-     * behaves as though it invokes <code>{@link #print(char[])}</code> and then
-     * <code>{@link #println()}</code>.
+     * behaves as though it invokes {@link #print(char[])} and then
+     * {@link #println()}.
      *
-     * @param x the array of <code>char</code> values to be printed
+     * @param x the array of {@code char} values to be printed
      */
     public void println(char x[]) {
         synchronized (lock) {
@@ -729,10 +812,10 @@
 
     /**
      * Prints a String and then terminates the line.  This method behaves as
-     * though it invokes <code>{@link #print(String)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(String)} and then
+     * {@link #println()}.
      *
-     * @param x the <code>String</code> value to be printed
+     * @param x the {@code String} value to be printed
      */
     public void println(String x) {
         synchronized (lock) {
@@ -745,10 +828,10 @@
      * Prints an Object and then terminates the line.  This method calls
      * at first String.valueOf(x) to get the printed object's string value,
      * then behaves as
-     * though it invokes <code>{@link #print(String)}</code> and then
-     * <code>{@link #println()}</code>.
+     * though it invokes {@link #print(String)} and then
+     * {@link #println()}.
      *
-     * @param x  The <code>Object</code> to be printed.
+     * @param x  The {@code Object} to be printed.
      */
     public void println(Object x) {
         String s = String.valueOf(x);
@@ -763,11 +846,13 @@
      * the specified format string and arguments.  If automatic flushing is
      * enabled, calls to this method will flush the output buffer.
      *
-     * <p> An invocation of this method of the form <tt>out.printf(format,
-     * args)</tt> behaves in exactly the same way as the invocation
+     * <p> An invocation of this method of the form
+     * {@code out.printf(format, args)}
+     * behaves in exactly the same way as the invocation
      *
-     * <pre>
-     *     out.format(format, args) </pre>
+     * <pre>{@code
+     *     out.format(format, args)
+     * }</pre>
      *
      * @param  format
      *         A format string as described in <a
@@ -781,7 +866,7 @@
      *         limited by the maximum dimension of a Java array as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *         The behaviour on a
-     *         <tt>null</tt> argument depends on the <a
+     *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
      * @throws  java.util.IllegalFormatException
@@ -794,7 +879,7 @@
      *          formatter class specification.
      *
      * @throws  NullPointerException
-     *          If the <tt>format</tt> is <tt>null</tt>
+     *          If the {@code format} is {@code null}
      *
      * @return  This writer
      *
@@ -809,15 +894,17 @@
      * the specified format string and arguments.  If automatic flushing is
      * enabled, calls to this method will flush the output buffer.
      *
-     * <p> An invocation of this method of the form <tt>out.printf(l, format,
-     * args)</tt> behaves in exactly the same way as the invocation
+     * <p> An invocation of this method of the form
+     * {@code out.printf(l, format, args)}
+     * behaves in exactly the same way as the invocation
      *
-     * <pre>
-     *     out.format(l, format, args) </pre>
+     * <pre>{@code
+     *     out.format(l, format, args)
+     * }</pre>
      *
      * @param  l
      *         The {@linkplain java.util.Locale locale} to apply during
-     *         formatting.  If <tt>l</tt> is <tt>null</tt> then no localization
+     *         formatting.  If {@code l} is {@code null} then no localization
      *         is applied.
      *
      * @param  format
@@ -832,7 +919,7 @@
      *         limited by the maximum dimension of a Java array as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *         The behaviour on a
-     *         <tt>null</tt> argument depends on the <a
+     *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
      * @throws  java.util.IllegalFormatException
@@ -845,7 +932,7 @@
      *          formatter class specification.
      *
      * @throws  NullPointerException
-     *          If the <tt>format</tt> is <tt>null</tt>
+     *          If the {@code format} is {@code null}
      *
      * @return  This writer
      *
@@ -876,7 +963,7 @@
      *         limited by the maximum dimension of a Java array as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *         The behaviour on a
-     *         <tt>null</tt> argument depends on the <a
+     *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
      * @throws  java.util.IllegalFormatException
@@ -889,7 +976,7 @@
      *          Formatter class specification.
      *
      * @throws  NullPointerException
-     *          If the <tt>format</tt> is <tt>null</tt>
+     *          If the {@code format} is {@code null}
      *
      * @return  This writer
      *
@@ -921,7 +1008,7 @@
      *
      * @param  l
      *         The {@linkplain java.util.Locale locale} to apply during
-     *         formatting.  If <tt>l</tt> is <tt>null</tt> then no localization
+     *         formatting.  If {@code l} is {@code null} then no localization
      *         is applied.
      *
      * @param  format
@@ -936,7 +1023,7 @@
      *         limited by the maximum dimension of a Java array as defined by
      *         <cite>The Java&trade; Virtual Machine Specification</cite>.
      *         The behaviour on a
-     *         <tt>null</tt> argument depends on the <a
+     *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
      * @throws  java.util.IllegalFormatException
@@ -949,7 +1036,7 @@
      *          formatter class specification.
      *
      * @throws  NullPointerException
-     *          If the <tt>format</tt> is <tt>null</tt>
+     *          If the {@code format} is {@code null}
      *
      * @return  This writer
      *
@@ -976,21 +1063,22 @@
     /**
      * Appends the specified character sequence to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * <p> An invocation of this method of the form {@code out.append(csq)}
      * behaves in exactly the same way as the invocation
      *
-     * <pre>
-     *     out.write(csq.toString()) </pre>
+     * <pre>{@code
+     *     out.write(csq.toString())
+     * }</pre>
      *
-     * <p> Depending on the specification of <tt>toString</tt> for the
-     * character sequence <tt>csq</tt>, the entire sequence may not be
-     * appended. For instance, invoking the <tt>toString</tt> method of a
+     * <p> Depending on the specification of {@code toString} for the
+     * character sequence {@code csq}, the entire sequence may not be
+     * appended. For instance, invoking the {@code toString} method of a
      * character buffer will return a subsequence whose content depends upon
      * the buffer's position and limit.
      *
      * @param  csq
-     *         The character sequence to append.  If <tt>csq</tt> is
-     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         The character sequence to append.  If {@code csq} is
+     *         {@code null}, then the four characters {@code "null"} are
      *         appended to this writer.
      *
      * @return  This writer
@@ -998,28 +1086,27 @@
      * @since  1.5
      */
     public PrintWriter append(CharSequence csq) {
-        if (csq == null)
-            write("null");
-        else
-            write(csq.toString());
+        write(String.valueOf(csq));
         return this;
     }
 
     /**
      * Appends a subsequence of the specified character sequence to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq, start,
-     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * <p> An invocation of this method of the form
+     * {@code out.append(csq, start, end)}
+     * when {@code csq} is not {@code null}, behaves in
      * exactly the same way as the invocation
      *
-     * <pre>
-     *     out.write(csq.subSequence(start, end).toString()) </pre>
+     * <pre>{@code
+     *     out.write(csq.subSequence(start, end).toString())
+     * }</pre>
      *
      * @param  csq
      *         The character sequence from which a subsequence will be
-     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
-     *         will be appended as if <tt>csq</tt> contained the four
-     *         characters <tt>"null"</tt>.
+     *         appended.  If {@code csq} is {@code null}, then characters
+     *         will be appended as if {@code csq} contained the four
+     *         characters {@code "null"}.
      *
      * @param  start
      *         The index of the first character in the subsequence
@@ -1031,26 +1118,26 @@
      * @return  This writer
      *
      * @throws  IndexOutOfBoundsException
-     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
-     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
-     *          <tt>csq.length()</tt>
+     *          If {@code start} or {@code end} are negative, {@code start}
+     *          is greater than {@code end}, or {@code end} is greater than
+     *          {@code csq.length()}
      *
      * @since  1.5
      */
     public PrintWriter append(CharSequence csq, int start, int end) {
-        CharSequence cs = (csq == null ? "null" : csq);
-        write(cs.subSequence(start, end).toString());
-        return this;
+        if (csq == null) csq = "null";
+        return append(csq.subSequence(start, end));
     }
 
     /**
      * Appends the specified character to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * <p> An invocation of this method of the form {@code out.append(c)}
      * behaves in exactly the same way as the invocation
      *
-     * <pre>
-     *     out.write(c) </pre>
+     * <pre>{@code
+     *     out.write(c)
+     * }</pre>
      *
      * @param  c
      *         The 16-bit character to append
diff --git a/ojluni/src/main/java/java/io/Reader.java b/ojluni/src/main/java/java/io/Reader.java
index 1c9cca6..fd3a87f 100644
--- a/ojluni/src/main/java/java/io/Reader.java
+++ b/ojluni/src/main/java/java/io/Reader.java
@@ -26,6 +26,9 @@
 package java.io;
 
 
+import java.nio.CharBuffer;
+import java.util.Objects;
+
 /**
  * Abstract class for reading character streams.  The only methods that a
  * subclass must implement are read(char[], int, int) and close().  Most
@@ -45,16 +48,102 @@
  * @see Writer
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public abstract class Reader implements Readable, Closeable {
 
+    private static final int TRANSFER_BUFFER_SIZE = 8192;
+
+    /**
+     * Returns a new {@code Reader} that reads no characters. The returned
+     * stream is initially open.  The stream is closed by calling the
+     * {@code close()} method.  Subsequent calls to {@code close()} have no
+     * effect.
+     *
+     * <p> While the stream is open, the {@code read()}, {@code read(char[])},
+     * {@code read(char[], int, int)}, {@code read(Charbuffer)}, {@code
+     * ready()}, {@code skip(long)}, and {@code transferTo()} methods all
+     * behave as if end of stream has been reached. After the stream has been
+     * closed, these methods all throw {@code IOException}.
+     *
+     * <p> The {@code markSupported()} method returns {@code false}.  The
+     * {@code mark()} and {@code reset()} methods throw an {@code IOException}.
+     *
+     * <p> The {@link #lock object} used to synchronize operations on the
+     * returned {@code Reader} is not specified.
+     *
+     * @return a {@code Reader} which reads no characters
+     *
+     * @since 11
+     */
+    public static Reader nullReader() {
+        return new Reader() {
+            private volatile boolean closed;
+
+            private void ensureOpen() throws IOException {
+                if (closed) {
+                    throw new IOException("Stream closed");
+                }
+            }
+
+            @Override
+            public int read() throws IOException {
+                ensureOpen();
+                return -1;
+            }
+
+            @Override
+            public int read(char[] cbuf, int off, int len) throws IOException {
+                Objects.checkFromIndexSize(off, len, cbuf.length);
+                ensureOpen();
+                if (len == 0) {
+                    return 0;
+                }
+                return -1;
+            }
+
+            @Override
+            public int read(CharBuffer target) throws IOException {
+                Objects.requireNonNull(target);
+                ensureOpen();
+                if (target.hasRemaining()) {
+                    return -1;
+                }
+                return 0;
+            }
+
+            @Override
+            public boolean ready() throws IOException {
+                ensureOpen();
+                return false;
+            }
+
+            @Override
+            public long skip(long n) throws IOException {
+                ensureOpen();
+                return 0L;
+            }
+
+            @Override
+            public long transferTo(Writer out) throws IOException {
+                Objects.requireNonNull(out);
+                ensureOpen();
+                return 0L;
+            }
+
+            @Override
+            public void close() {
+                closed = true;
+            }
+        };
+    }
+
     /**
      * The object used to synchronize operations on this stream.  For
      * efficiency, a character-stream object may use an object other than
      * itself to protect critical sections.  A subclass should therefore use
-     * the object in this field rather than <tt>this</tt> or a synchronized
+     * the object in this field rather than {@code this} or a synchronized
      * method.
      */
     protected Object lock;
@@ -111,7 +200,7 @@
      * should override this method.
      *
      * @return     The character read, as an integer in the range 0 to 65535
-     *             (<tt>0x00-0xffff</tt>), or -1 if the end of the stream has
+     *             ({@code 0x00-0xffff}), or -1 if the end of the stream has
      *             been reached
      *
      * @exception  IOException  If an I/O error occurs
@@ -153,8 +242,11 @@
      *             stream has been reached
      *
      * @exception  IOException  If an I/O error occurs
+     * @exception  IndexOutOfBoundsException
+     *             If {@code off} is negative, or {@code len} is negative,
+     *             or {@code len} is greater than {@code cbuf.length - off}
      */
-    abstract public int read(char cbuf[], int off, int len) throws IOException;
+    public abstract int read(char cbuf[], int off, int len) throws IOException;
 
     /** Maximum skip-buffer size */
     private static final int maxSkipBufferSize = 8192;
@@ -257,6 +349,43 @@
      *
      * @exception  IOException  If an I/O error occurs
      */
-     abstract public void close() throws IOException;
+     public abstract void close() throws IOException;
+
+    /**
+     * Reads all characters from this reader and writes the characters to the
+     * given writer in the order that they are read. On return, this reader
+     * will be at end of the stream. This method does not close either reader
+     * or writer.
+     * <p>
+     * This method may block indefinitely reading from the reader, or
+     * writing to the writer. The behavior for the case where the reader
+     * and/or writer is <i>asynchronously closed</i>, or the thread
+     * interrupted during the transfer, is highly reader and writer
+     * specific, and therefore not specified.
+     * <p>
+     * If an I/O error occurs reading from the reader or writing to the
+     * writer, then it may do so after some characters have been read or
+     * written. Consequently the reader may not be at end of the stream and
+     * one, or both, streams may be in an inconsistent state. It is strongly
+     * recommended that both streams be promptly closed if an I/O error occurs.
+     *
+     * @param  out the writer, non-null
+     * @return the number of characters transferred
+     * @throws IOException if an I/O error occurs when reading or writing
+     * @throws NullPointerException if {@code out} is {@code null}
+     *
+     * @since 10
+     */
+    public long transferTo(Writer out) throws IOException {
+        Objects.requireNonNull(out, "out");
+        long transferred = 0;
+        char[] buffer = new char[TRANSFER_BUFFER_SIZE];
+        int nRead;
+        while ((nRead = read(buffer, 0, TRANSFER_BUFFER_SIZE)) >= 0) {
+            out.write(buffer, 0, nRead);
+            transferred += nRead;
+        }
+        return transferred;
+    }
 
 }
diff --git a/ojluni/src/main/java/java/io/Writer.java b/ojluni/src/main/java/java/io/Writer.java
index 8747a13..f83a618 100644
--- a/ojluni/src/main/java/java/io/Writer.java
+++ b/ojluni/src/main/java/java/io/Writer.java
@@ -26,25 +26,26 @@
 package java.io;
 
 
+import java.util.Objects;
+
 /**
  * Abstract class for writing to character streams.  The only methods that a
  * subclass must implement are write(char[], int, int), flush(), and close().
  * Most subclasses, however, will override some of the methods defined here in
  * order to provide higher efficiency, additional functionality, or both.
  *
- * @see Writer
  * @see   BufferedWriter
  * @see   CharArrayWriter
  * @see   FilterWriter
  * @see   OutputStreamWriter
- * @see     FileWriter
+ * @see   FileWriter
  * @see   PipedWriter
  * @see   PrintWriter
  * @see   StringWriter
  * @see Reader
  *
  * @author      Mark Reinhold
- * @since       JDK1.1
+ * @since       1.1
  */
 
 public abstract class Writer implements Appendable, Closeable, Flushable {
@@ -60,10 +61,95 @@
     private static final int WRITE_BUFFER_SIZE = 1024;
 
     /**
+     * Returns a new {@code Writer} which discards all characters.  The
+     * returned stream is initially open.  The stream is closed by calling
+     * the {@code close()} method.  Subsequent calls to {@code close()} have
+     * no effect.
+     *
+     * <p> While the stream is open, the {@code append(char)}, {@code
+     * append(CharSequence)}, {@code append(CharSequence, int, int)},
+     * {@code flush()}, {@code write(int)}, {@code write(char[])}, and
+     * {@code write(char[], int, int)} methods do nothing. After the stream
+     * has been closed, these methods all throw {@code IOException}.
+     *
+     * <p> The {@link #lock object} used to synchronize operations on the
+     * returned {@code Writer} is not specified.
+     *
+     * @return a {@code Writer} which discards all characters
+     *
+     * @since 11
+     */
+    public static Writer nullWriter() {
+        return new Writer() {
+            private volatile boolean closed;
+
+            private void ensureOpen() throws IOException {
+                if (closed) {
+                    throw new IOException("Stream closed");
+                }
+            }
+
+            @Override
+            public Writer append(char c) throws IOException {
+                ensureOpen();
+                return this;
+            }
+
+            @Override
+            public Writer append(CharSequence csq) throws IOException {
+                ensureOpen();
+                return this;
+            }
+
+            @Override
+            public Writer append(CharSequence csq, int start, int end) throws IOException {
+                ensureOpen();
+                if (csq != null) {
+                    Objects.checkFromToIndex(start, end, csq.length());
+                }
+                return this;
+            }
+
+            @Override
+            public void write(int c) throws IOException {
+                ensureOpen();
+            }
+
+            @Override
+            public void write(char[] cbuf, int off, int len) throws IOException {
+                Objects.checkFromIndexSize(off, len, cbuf.length);
+                ensureOpen();
+            }
+
+            @Override
+            public void write(String str) throws IOException {
+                Objects.requireNonNull(str);
+                ensureOpen();
+            }
+
+            @Override
+            public void write(String str, int off, int len) throws IOException {
+                Objects.checkFromIndexSize(off, len, str.length());
+                ensureOpen();
+            }
+
+            @Override
+            public void flush() throws IOException {
+                ensureOpen();
+            }
+
+            @Override
+            public void close() throws IOException {
+                closed = true;
+            }
+        };
+    }
+
+    /**
      * The object used to synchronize operations on this stream.  For
      * efficiency, a character-stream object may use an object other than
      * itself to protect critical sections.  A subclass should therefore use
-     * the object in this field rather than <tt>this</tt> or a synchronized
+     * the object in this field rather than {@code this} or a synchronized
      * method.
      */
     protected Object lock;
@@ -139,10 +225,16 @@
      * @param  len
      *         Number of characters to write
      *
+     * @throws  IndexOutOfBoundsException
+     *          Implementations should throw this exception
+     *          if {@code off} is negative, or {@code len} is negative,
+     *          or {@code off + len} is negative or greater than the length
+     *          of the given array
+     *
      * @throws  IOException
      *          If an I/O error occurs
      */
-    abstract public void write(char cbuf[], int off, int len) throws IOException;
+    public abstract void write(char cbuf[], int off, int len) throws IOException;
 
     /**
      * Writes a string.
@@ -160,6 +252,11 @@
     /**
      * Writes a portion of a string.
      *
+     * @implSpec
+     * The implementation in this class throws an
+     * {@code IndexOutOfBoundsException} for the indicated conditions;
+     * overriding methods may choose to do otherwise.
+     *
      * @param  str
      *         A String
      *
@@ -170,8 +267,9 @@
      *         Number of characters to write
      *
      * @throws  IndexOutOfBoundsException
-     *          If <tt>off</tt> is negative, or <tt>len</tt> is negative,
-     *          or <tt>off+len</tt> is negative or greater than the length
+     *          Implementations should throw this exception
+     *          if {@code off} is negative, or {@code len} is negative,
+     *          or {@code off + len} is negative or greater than the length
      *          of the given string
      *
      * @throws  IOException
@@ -196,21 +294,21 @@
     /**
      * Appends the specified character sequence to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * <p> An invocation of this method of the form {@code out.append(csq)}
      * behaves in exactly the same way as the invocation
      *
      * <pre>
      *     out.write(csq.toString()) </pre>
      *
-     * <p> Depending on the specification of <tt>toString</tt> for the
-     * character sequence <tt>csq</tt>, the entire sequence may not be
-     * appended. For instance, invoking the <tt>toString</tt> method of a
+     * <p> Depending on the specification of {@code toString} for the
+     * character sequence {@code csq}, the entire sequence may not be
+     * appended. For instance, invoking the {@code toString} method of a
      * character buffer will return a subsequence whose content depends upon
      * the buffer's position and limit.
      *
      * @param  csq
-     *         The character sequence to append.  If <tt>csq</tt> is
-     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         The character sequence to append.  If {@code csq} is
+     *         {@code null}, then the four characters {@code "null"} are
      *         appended to this writer.
      *
      * @return  This writer
@@ -221,29 +319,28 @@
      * @since  1.5
      */
     public Writer append(CharSequence csq) throws IOException {
-        if (csq == null)
-            write("null");
-        else
-            write(csq.toString());
+        write(String.valueOf(csq));
         return this;
     }
 
     /**
      * Appends a subsequence of the specified character sequence to this writer.
-     * <tt>Appendable</tt>.
+     * {@code Appendable}.
      *
-     * <p> An invocation of this method of the form <tt>out.append(csq, start,
-     * end)</tt> when <tt>csq</tt> is not <tt>null</tt> behaves in exactly the
+     * <p> An invocation of this method of the form
+     * {@code out.append(csq, start, end)} when {@code csq}
+     * is not {@code null} behaves in exactly the
      * same way as the invocation
      *
-     * <pre>
-     *     out.write(csq.subSequence(start, end).toString()) </pre>
+     * <pre>{@code
+     *     out.write(csq.subSequence(start, end).toString())
+     * }</pre>
      *
      * @param  csq
      *         The character sequence from which a subsequence will be
-     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
-     *         will be appended as if <tt>csq</tt> contained the four
-     *         characters <tt>"null"</tt>.
+     *         appended.  If {@code csq} is {@code null}, then characters
+     *         will be appended as if {@code csq} contained the four
+     *         characters {@code "null"}.
      *
      * @param  start
      *         The index of the first character in the subsequence
@@ -255,9 +352,9 @@
      * @return  This writer
      *
      * @throws  IndexOutOfBoundsException
-     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
-     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
-     *          <tt>csq.length()</tt>
+     *          If {@code start} or {@code end} are negative, {@code start}
+     *          is greater than {@code end}, or {@code end} is greater than
+     *          {@code csq.length()}
      *
      * @throws  IOException
      *          If an I/O error occurs
@@ -265,15 +362,14 @@
      * @since  1.5
      */
     public Writer append(CharSequence csq, int start, int end) throws IOException {
-        CharSequence cs = (csq == null ? "null" : csq);
-        write(cs.subSequence(start, end).toString());
-        return this;
+        if (csq == null) csq = "null";
+        return append(csq.subSequence(start, end));
     }
 
     /**
      * Appends the specified character to this writer.
      *
-     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * <p> An invocation of this method of the form {@code out.append(c)}
      * behaves in exactly the same way as the invocation
      *
      * <pre>
@@ -310,7 +406,7 @@
      * @throws  IOException
      *          If an I/O error occurs
      */
-    abstract public void flush() throws IOException;
+    public abstract void flush() throws IOException;
 
     /**
      * Closes the stream, flushing it first. Once the stream has been closed,
@@ -320,6 +416,6 @@
      * @throws  IOException
      *          If an I/O error occurs
      */
-    abstract public void close() throws IOException;
+    public abstract void close() throws IOException;
 
 }
diff --git a/ojluni/src/main/java/java/lang/Boolean.java b/ojluni/src/main/java/java/lang/Boolean.java
index bfd704f..c600a06 100644
--- a/ojluni/src/main/java/java/lang/Boolean.java
+++ b/ojluni/src/main/java/java/lang/Boolean.java
@@ -25,6 +25,8 @@
 
 package java.lang;
 
+import jdk.internal.HotSpotIntrinsicCandidate;
+
 /**
  * The Boolean class wraps a value of the primitive type
  * {@code boolean} in an object. An object of type
@@ -136,8 +138,7 @@
      *
      * @return  the primitive {@code boolean} value of this object.
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public boolean booleanValue() {
         return value;
     }
@@ -156,8 +157,7 @@
      * @return a {@code Boolean} instance representing {@code b}.
      * @since  1.4
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static Boolean valueOf(boolean b) {
         return (b ? TRUE : FALSE);
     }
diff --git a/ojluni/src/main/java/java/lang/Byte.java b/ojluni/src/main/java/java/lang/Byte.java
index bc397f9..9988333 100644
--- a/ojluni/src/main/java/java/lang/Byte.java
+++ b/ojluni/src/main/java/java/lang/Byte.java
@@ -25,8 +25,7 @@
 
 package java.lang;
 
-// Android-removed: Unsupported @HotSpotIntrinsicCandidate annotation.
-// import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.HotSpotIntrinsicCandidate;
 import libcore.util.HexEncoding;
 
 /**
@@ -102,8 +101,7 @@
      * @return a {@code Byte} instance representing {@code b}.
      * @since  1.5
      */
-    // Android-removed: Unsupported @HotSpotIntrinsicCandidate annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static Byte valueOf(byte b) {
         final int offset = 128;
         return ByteCache.cache[(int)b + offset];
@@ -338,8 +336,7 @@
      * Returns the value of this {@code Byte} as a
      * {@code byte}.
      */
-    // Android-removed: Unsupported @HotSpotIntrinsicCandidate annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public byte byteValue() {
         return value;
     }
diff --git a/ojluni/src/main/java/java/lang/Class.java b/ojluni/src/main/java/java/lang/Class.java
index 7925408..722968c 100644
--- a/ojluni/src/main/java/java/lang/Class.java
+++ b/ojluni/src/main/java/java/lang/Class.java
@@ -2396,6 +2396,8 @@
      * assertion status that was (or will be) associated with the specified
      * class when it was (or will be) initialized.
      *
+     * Android-note: AssertionStatuses are unsupported. This method will always return false.
+     *
      * @return the desired assertion status of the specified class.
      * @see    java.lang.ClassLoader#setClassAssertionStatus
      * @see    java.lang.ClassLoader#setPackageAssertionStatus
diff --git a/ojluni/src/main/java/java/lang/ClassLoader.java b/ojluni/src/main/java/java/lang/ClassLoader.java
index 0a8b08a..6c01ffa 100644
--- a/ojluni/src/main/java/java/lang/ClassLoader.java
+++ b/ojluni/src/main/java/java/lang/ClassLoader.java
@@ -1242,6 +1242,8 @@
      * invoking {@link #setPackageAssertionStatus(String, boolean)} or {@link
      * #setClassAssertionStatus(String, boolean)}.
      *
+     * Android-note: AssertionStatuses are unsupported. This method is a no-op.
+     *
      * @param  enabled
      *         <tt>true</tt> if classes loaded by this class loader will
      *         henceforth have assertions enabled by default, <tt>false</tt>
@@ -1274,6 +1276,8 @@
      * assertion status, and may be overridden on a per-class basis by invoking
      * {@link #setClassAssertionStatus(String, boolean)}.  </p>
      *
+     * Android-note: AssertionStatuses are unsupported. This method is a no-op.
+     *
      * @param  packageName
      *         The name of the package whose package default assertion status
      *         is to be set. A <tt>null</tt> value indicates the unnamed
@@ -1304,6 +1308,8 @@
      * <p> If the named class is not a top-level class, this invocation will
      * have no effect on the actual assertion status of any class. </p>
      *
+     * Android-note: AssertionStatuses are unsupported. This method is a no-op.
+     *
      * @param  className
      *         The fully qualified class name of the top-level class whose
      *         assertion status is to be set.
@@ -1325,6 +1331,8 @@
      * provided so that class loaders can be made to ignore any command line or
      * persistent assertion status settings and "start with a clean slate."
      *
+     * Android-note: AssertionStatuses are unsupported. This method is a no-op.
+     *
      * @since  1.4
      */
     public void clearAssertionStatus() {
diff --git a/ojluni/src/main/java/java/lang/Double.java b/ojluni/src/main/java/java/lang/Double.java
index 35e1f52..52bf32c 100644
--- a/ojluni/src/main/java/java/lang/Double.java
+++ b/ojluni/src/main/java/java/lang/Double.java
@@ -27,8 +27,7 @@
 
 import jdk.internal.math.FloatingDecimal;
 import jdk.internal.math.DoubleConsts;
-// Android-removed: HotSpotIntrinsicCandidate
-// import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
  * The {@code Double} class wraps a value of the primitive type
@@ -520,8 +519,7 @@
      * @return a {@code Double} instance representing {@code d}.
      * @since  1.5
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static Double valueOf(double d) {
         return new Double(d);
     }
@@ -731,8 +729,7 @@
      *
      * @return the {@code double} value represented by this object
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public double doubleValue() {
         return value;
     }
@@ -853,8 +850,7 @@
      * @param   value   a {@code double} precision floating-point number.
      * @return the bits that represent the floating-point number.
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static long doubleToLongBits(double value) {
         if (!isNaN(value)) {
             return doubleToRawLongBits(value);
@@ -898,8 +894,7 @@
      * @return the bits that represent the floating-point number.
      * @since 1.3
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static native long doubleToRawLongBits(double value);
 
     /**
@@ -963,8 +958,7 @@
      * @return  the {@code double} floating-point value with the same
      *          bit pattern.
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static native double longBitsToDouble(long bits);
 
     /**
diff --git a/ojluni/src/main/java/java/lang/Float.java b/ojluni/src/main/java/java/lang/Float.java
index b24af88..52cb2c0 100644
--- a/ojluni/src/main/java/java/lang/Float.java
+++ b/ojluni/src/main/java/java/lang/Float.java
@@ -26,8 +26,7 @@
 package java.lang;
 
 import jdk.internal.math.FloatingDecimal;
-// Android-removed: HotSpotIntrinsicCandidate
-// import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
  * The {@code Float} class wraps a value of primitive type
@@ -433,8 +432,7 @@
      * @return a {@code Float} instance representing {@code f}.
      * @since  1.5
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static Float valueOf(float f) {
         return new Float(f);
     }
@@ -646,8 +644,7 @@
      *
      * @return the {@code float} value represented by this object
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public float floatValue() {
         return value;
     }
@@ -766,8 +763,7 @@
      * @param   value   a floating-point number.
      * @return the bits that represent the floating-point number.
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int floatToIntBits(float value) {
         if (!isNaN(value)) {
             return floatToRawIntBits(value);
@@ -810,8 +806,7 @@
      * @return the bits that represent the floating-point number.
      * @since 1.3
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static native int floatToRawIntBits(float value);
 
     /**
@@ -873,8 +868,7 @@
      * @return  the {@code float} floating-point value with the same bit
      *          pattern.
      */
-    // Android-removed: HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static native float intBitsToFloat(int bits);
 
     /**
diff --git a/ojluni/src/main/java/java/lang/Math.java b/ojluni/src/main/java/java/lang/Math.java
index ea38fab..e446371c 100644
--- a/ojluni/src/main/java/java/lang/Math.java
+++ b/ojluni/src/main/java/java/lang/Math.java
@@ -30,9 +30,9 @@
 
 import java.math.BigDecimal;
 import java.util.Random;
-
 import jdk.internal.math.FloatConsts;
 import jdk.internal.math.DoubleConsts;
+import jdk.internal.HotSpotIntrinsicCandidate;
 
 // Android-note: Document that the results from Math are based on libm's behavior.
 // For performance, Android implements many of the methods in this class in terms of the underlying
@@ -964,8 +964,7 @@
      * @throws ArithmeticException if the result overflows an int
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int addExact(int x, int y) {
         int r = x + y;
         // HD 2-12 Overflow iff both arguments have the opposite sign of the result
@@ -985,8 +984,7 @@
      * @throws ArithmeticException if the result overflows a long
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static long addExact(long x, long y) {
         long r = x + y;
         // HD 2-12 Overflow iff both arguments have the opposite sign of the result
@@ -1006,8 +1004,7 @@
      * @throws ArithmeticException if the result overflows an int
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int subtractExact(int x, int y) {
         int r = x - y;
         // HD 2-12 Overflow iff the arguments have different signs and
@@ -1028,8 +1025,7 @@
      * @throws ArithmeticException if the result overflows a long
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static long subtractExact(long x, long y) {
         long r = x - y;
         // HD 2-12 Overflow iff the arguments have different signs and
@@ -1050,8 +1046,7 @@
      * @throws ArithmeticException if the result overflows an int
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int multiplyExact(int x, int y) {
         long r = (long)x * (long)y;
         if ((int)r != r) {
@@ -1084,8 +1079,7 @@
      * @throws ArithmeticException if the result overflows a long
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static long multiplyExact(long x, long y) {
         long r = x * y;
         long ax = Math.abs(x);
@@ -1111,8 +1105,7 @@
      * @throws ArithmeticException if the result overflows an int
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int incrementExact(int a) {
         if (a == Integer.MAX_VALUE) {
             throw new ArithmeticException("integer overflow");
@@ -1130,8 +1123,7 @@
      * @throws ArithmeticException if the result overflows a long
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static long incrementExact(long a) {
         if (a == Long.MAX_VALUE) {
             throw new ArithmeticException("long overflow");
@@ -1149,8 +1141,7 @@
      * @throws ArithmeticException if the result overflows an int
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int decrementExact(int a) {
         if (a == Integer.MIN_VALUE) {
             throw new ArithmeticException("integer overflow");
@@ -1168,8 +1159,7 @@
      * @throws ArithmeticException if the result overflows a long
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static long decrementExact(long a) {
         if (a == Long.MIN_VALUE) {
             throw new ArithmeticException("long overflow");
@@ -1187,8 +1177,7 @@
      * @throws ArithmeticException if the result overflows an int
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int negateExact(int a) {
         if (a == Integer.MIN_VALUE) {
             throw new ArithmeticException("integer overflow");
@@ -1206,8 +1195,7 @@
      * @throws ArithmeticException if the result overflows a long
      * @since 1.8
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static long negateExact(long a) {
         if (a == Long.MIN_VALUE) {
             throw new ArithmeticException("long overflow");
@@ -1253,8 +1241,7 @@
      * @return the result
      * @since 9
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static long multiplyHigh(long x, long y) {
         if (x < 0 || y < 0) {
             // Use technique from section 8-2 of Henry S. Warren, Jr.,
@@ -1574,8 +1561,7 @@
      * @param   a   the argument whose absolute value is to be determined
      * @return  the absolute value of the argument.
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static double abs(double a) {
         // Android-changed: Implementation modified to exactly match ART intrinsics behavior.
         // Note, as a "quality of implementation", rather than pure "spec compliance",
@@ -1596,8 +1582,7 @@
      * @param   b   another argument.
      * @return  the larger of {@code a} and {@code b}.
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int max(int a, int b) {
         return (a >= b) ? a : b;
     }
@@ -1682,8 +1667,7 @@
      * @param   b   another argument.
      * @return  the smaller of {@code a} and {@code b}.
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int min(int a, int b) {
         return (a <= b) ? a : b;
     }
@@ -1804,8 +1788,7 @@
      *
      * @since 9
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static double fma(double a, double b, double c) {
         /*
          * Infinity and NaN arithmetic is not quite the same with two
@@ -1922,8 +1905,7 @@
      *
      * @since 9
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static float fma(float a, float b, float c) {
         /*
          *  Since the double format has more than twice the precision
diff --git a/ojluni/src/main/java/java/lang/Short.java b/ojluni/src/main/java/java/lang/Short.java
index dd6e2e2..57b291f 100644
--- a/ojluni/src/main/java/java/lang/Short.java
+++ b/ojluni/src/main/java/java/lang/Short.java
@@ -25,8 +25,7 @@
 
 package java.lang;
 
-// Android-removed: unsupported @HotSpotIntrinsicCandidate annotation.
-// import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
  * The {@code Short} class wraps a value of primitive type {@code
@@ -230,8 +229,7 @@
      * @return a {@code Short} instance representing {@code s}.
      * @since  1.5
      */
-    // Android-removed: unsupported @HotSpotIntrinsicCandidate annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static Short valueOf(short s) {
         final int offset = 128;
         int sAsInt = s;
@@ -351,8 +349,7 @@
      * Returns the value of this {@code Short} as a
      * {@code short}.
      */
-    // Android-removed: unsupported @HotSpotIntrinsicCandidate annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public short shortValue() {
         return value;
     }
@@ -522,8 +519,7 @@
      *     the bytes in the specified {@code short} value.
      * @since 1.5
      */
-    // Android-removed: unsupported @HotSpotIntrinsicCandidate annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static short reverseBytes(short i) {
         return (short) (((i & 0xFF00) >> 8) | (i << 8));
     }
diff --git a/ojluni/src/main/java/java/lang/StrictMath.java b/ojluni/src/main/java/java/lang/StrictMath.java
index 8ebf741..2c9f497 100644
--- a/ojluni/src/main/java/java/lang/StrictMath.java
+++ b/ojluni/src/main/java/java/lang/StrictMath.java
@@ -27,6 +27,7 @@
 
 import java.util.Random;
 import jdk.internal.math.DoubleConsts;
+import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
  * The class {@code StrictMath} contains methods for performing basic
@@ -287,8 +288,7 @@
      * @param   a   a value.
      * @return  the positive square root of {@code a}.
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static native double sqrt(double a);
 
     /**
@@ -1136,8 +1136,7 @@
      * @param   b   another argument.
      * @return  the larger of {@code a} and {@code b}.
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int max(int a, int b) {
         return Math.max(a, b);
     }
@@ -1202,8 +1201,7 @@
      * @param   b   another argument.
      * @return  the smaller of {@code a} and {@code b}.
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static int min(int a, int b) {
         return Math.min(a, b);
     }
diff --git a/ojluni/src/main/java/java/lang/String.java b/ojluni/src/main/java/java/lang/String.java
index 2ba7b1f..75583cc 100644
--- a/ojluni/src/main/java/java/lang/String.java
+++ b/ojluni/src/main/java/java/lang/String.java
@@ -112,22 +112,23 @@
 
 public final class String
     implements java.io.Serializable, Comparable<String>, CharSequence {
-
     // BEGIN Android-changed: The character data is managed by the runtime.
-    // We only keep track of the length here and compression here. This has several consequences
-    // throughout this class:
-    //  - References to value[i] are replaced by charAt(i).
-    //  - References to value.length are replaced by calls to length().
-    //  - Sometimes the result of length() is assigned to a local variable to avoid repeated calls.
-    //  - We skip several attempts at optimization where the values field was assigned to a local
-    //    variable to avoid the getfield opcode.
-    // These changes are not all marked individually.
-    //
-    // private final char value[];
-    //
-    // If STRING_COMPRESSION_ENABLED, count stores the length shifted one bit to the left with the
-    // lowest bit used to indicate whether or not the bytes are compressed (see GetFlaggedCount in
-    // the native code).
+    /*
+    We only keep track of the length here and compression here. This has several consequences
+    throughout this class:
+     - References to value[i] are replaced by charAt(i).
+     - References to value.length are replaced by calls to length().
+     - Sometimes the result of length() is assigned to a local variable to avoid repeated calls.
+     - We skip several attempts at optimization where the values field was assigned to a local
+       variable to avoid the getfield opcode.
+    These changes are not all marked individually.
+
+    If STRING_COMPRESSION_ENABLED, count stores the length shifted one bit to the left with the
+    lowest bit used to indicate whether or not the bytes are compressed (see GetFlaggedCount in
+    the native code).
+    /** The value is used for character storage. *
+    private final char value[];
+    */
     private final int count;
     // END Android-changed: The character data is managed by the runtime.
 
@@ -156,7 +157,8 @@
      * unnecessary since Strings are immutable.
      */
     public String() {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // Android-changed: Implemented as compiler and runtime intrinsics.
+        // this.value = "".value;
         throw new UnsupportedOperationException("Use StringFactory instead.");
     }
 
@@ -171,7 +173,9 @@
      *         A {@code String}
      */
     public String(String original) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // Android-changed: Implemented as compiler and runtime intrinsics.
+        // this.value = original.value;
+        // this.hash = original.hash;
         throw new UnsupportedOperationException("Use StringFactory instead.");
     }
 
@@ -185,7 +189,8 @@
      *         The initial value of the string
      */
     public String(char value[]) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // Android-changed: Implemented as compiler and runtime intrinsics.
+        // this.value = Arrays.copyOf(value, value.length);
         throw new UnsupportedOperationException("Use StringFactory instead.");
     }
 
@@ -211,8 +216,28 @@
      *          characters outside the bounds of the {@code value} array
      */
     public String(char value[], int offset, int count) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+        /*
+        if (offset < 0) {
+            throw new StringIndexOutOfBoundsException(offset);
+        }
+        if (count <= 0) {
+            if (count < 0) {
+                throw new StringIndexOutOfBoundsException(count);
+            }
+            if (offset <= value.length) {
+                this.value = "".value;
+                return;
+            }
+        }
+        // Note: offset or count might be near -1>>>1.
+        if (offset > value.length - count) {
+            throw new StringIndexOutOfBoundsException(offset + count);
+        }
+        this.value = Arrays.copyOfRange(value, offset, offset+count);
+        */
         throw new UnsupportedOperationException("Use StringFactory instead.");
+        // END Android-changed: Implemented as compiler and runtime intrinsics.
     }
 
     /**
@@ -244,8 +269,53 @@
      * @since  1.5
      */
     public String(int[] codePoints, int offset, int count) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+        /*
+        if (offset < 0) {
+            throw new StringIndexOutOfBoundsException(offset);
+        }
+        if (count <= 0) {
+            if (count < 0) {
+                throw new StringIndexOutOfBoundsException(count);
+            }
+            if (offset <= codePoints.length) {
+                this.value = "".value;
+                return;
+            }
+        }
+        // Note: offset or count might be near -1>>>1.
+        if (offset > codePoints.length - count) {
+            throw new StringIndexOutOfBoundsException(offset + count);
+        }
+
+        final int end = offset + count;
+
+        // Pass 1: Compute precise size of char[]
+        int n = count;
+        for (int i = offset; i < end; i++) {
+            int c = codePoints[i];
+            if (Character.isBmpCodePoint(c))
+                continue;
+            else if (Character.isValidCodePoint(c))
+                n++;
+            else throw new IllegalArgumentException(Integer.toString(c));
+        }
+
+        // Pass 2: Allocate and fill in char[]
+        final char[] v = new char[n];
+
+        for (int i = offset, j = 0; i < end; i++, j++) {
+            int c = codePoints[i];
+            if (Character.isBmpCodePoint(c))
+                v[j] = (char)c;
+            else
+                Character.toSurrogates(c, v, j++);
+        }
+
+        this.value = v;
+        */
         throw new UnsupportedOperationException("Use StringFactory instead.");
+        // END Android-changed: Implemented as compiler and runtime intrinsics.
     }
 
     /**
@@ -289,8 +359,25 @@
      */
     @Deprecated
     public String(byte ascii[], int hibyte, int offset, int count) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+        /*
+        checkBounds(ascii, offset, count);
+        char value[] = new char[count];
+
+        if (hibyte == 0) {
+            for (int i = count; i-- > 0;) {
+                value[i] = (char)(ascii[i + offset] & 0xff);
+            }
+        } else {
+            hibyte <<= 8;
+            for (int i = count; i-- > 0;) {
+                value[i] = (char)(hibyte | (ascii[i + offset] & 0xff));
+            }
+        }
+        this.value = value;
+        */
         throw new UnsupportedOperationException("Use StringFactory instead.");
+        // END Android-changed: Implemented as compiler and runtime intrinsics.
     }
 
     /**
@@ -325,10 +412,29 @@
      */
     @Deprecated
     public String(byte ascii[], int hibyte) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+        /*
+        this(ascii, hibyte, 0, ascii.length);
+        */
         throw new UnsupportedOperationException("Use StringFactory instead.");
+        // END Android-changed: Implemented as compiler and runtime intrinsics.
     }
 
+    // BEGIN Android-removed: checkBounds(byte[] bytes, int offset, int length) utility method.
+    /* Common private utility method used to bounds check the byte array
+     * and requested offset & length values used by the String(byte[],..)
+     * constructors.
+     *
+    private static void checkBounds(byte[] bytes, int offset, int length) {
+        if (length < 0)
+            throw new StringIndexOutOfBoundsException(length);
+        if (offset < 0)
+            throw new StringIndexOutOfBoundsException(offset);
+        if (offset > bytes.length - length)
+            throw new StringIndexOutOfBoundsException(offset + length);
+    }
+    // END Android-removed: checkBounds(byte[] bytes, int offset, int length) utility method.
+
     /**
      * Constructs a new {@code String} by decoding the specified subarray of
      * bytes using the specified charset.  The length of the new {@code String}
@@ -364,8 +470,15 @@
      */
     public String(byte bytes[], int offset, int length, String charsetName)
             throws UnsupportedEncodingException {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+        /*
+        if (charsetName == null)
+            throw new NullPointerException("charsetName");
+        checkBounds(bytes, offset, length);
+        this.value = StringCoding.decode(charsetName, bytes, offset, length);
+        */
         throw new UnsupportedOperationException("Use StringFactory instead.");
+        // END Android-changed: Implemented as compiler and runtime intrinsics.
     }
 
     /**
@@ -399,8 +512,15 @@
      * @since  1.6
      */
     public String(byte bytes[], int offset, int length, Charset charset) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+        /*
+        if (charset == null)
+            throw new NullPointerException("charset");
+        checkBounds(bytes, offset, length);
+        this.value =  StringCoding.decode(charset, bytes, offset, length);
+        */
         throw new UnsupportedOperationException("Use StringFactory instead.");
+        // END Android-changed: Implemented as compiler and runtime intrinsics.
     }
 
     /**
@@ -428,7 +548,8 @@
      */
     public String(byte bytes[], String charsetName)
             throws UnsupportedEncodingException {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // Android-changed: Implemented as compiler and runtime intrinsics.
+        // this(bytes, 0, bytes.length, charsetName);
         throw new UnsupportedOperationException("Use StringFactory instead.");
     }
 
@@ -453,7 +574,8 @@
      * @since  1.6
      */
     public String(byte bytes[], Charset charset) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // Android-changed: Implemented as compiler and runtime intrinsics.
+        // this(bytes, 0, bytes.length, charset);
         throw new UnsupportedOperationException("Use StringFactory instead.");
     }
 
@@ -484,7 +606,9 @@
      * @since  JDK1.1
      */
     public String(byte bytes[], int offset, int length) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // Android-changed: Implemented as compiler and runtime intrinsics.
+        // checkBounds(bytes, offset, length);
+        // this.value = StringCoding.decode(bytes, offset, length);
         throw new UnsupportedOperationException("Use StringFactory instead.");
     }
 
@@ -505,7 +629,8 @@
      * @since  JDK1.1
      */
     public String(byte bytes[]) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // Android-changed: Implemented as compiler and runtime intrinsics.
+        // this(bytes, 0, bytes.length);
         throw new UnsupportedOperationException("Use StringFactory instead.");
     }
 
@@ -519,8 +644,14 @@
      *         A {@code StringBuffer}
      */
     public String(StringBuffer buffer) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+        /*
+        synchronized(buffer) {
+            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
+        }
+        */
         throw new UnsupportedOperationException("Use StringFactory instead.");
+        // END Android-changed: Implemented as compiler and runtime intrinsics.
     }
 
     /**
@@ -539,11 +670,25 @@
      * @since  1.5
      */
     public String(StringBuilder builder) {
-        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        // Android-changed: Implemented as compiler and runtime intrinsics.
+        // this.value = Arrays.copyOf(builder.getValue(), builder.length());
         throw new UnsupportedOperationException("Use StringFactory instead.");
     }
 
-    // Android-removed: Unused package-private constructor String(char[] value, boolean share).
+    // BEGIN Android-removed: Unused package-private constructor String(char[] value, boolean share).
+    /*
+    /*
+    * Package private constructor which shares value array for speed.
+    * this constructor is always expected to be called with share==true.
+    * a separate constructor is needed because we already have a public
+    * String(char[]) constructor that makes a copy of the given char[].
+    *
+    String(char[] value, boolean share) {
+        // assert share : "unshared not supported";
+        this.value = value;
+    }
+    */
+    // END Android-removed: Unused package-private constructor String(char[] value, boolean share).
 
     // BEGIN Android-added: Constructor for internal use.
     // Not implemented in java as all calls are intercepted by the runtime.
@@ -568,7 +713,9 @@
      */
     public int length() {
         // BEGIN Android-changed: Get length from count field rather than value array (see above).
-        // return value.length;
+        /*
+        return value.length;
+        */
         final boolean STRING_COMPRESSION_ENABLED = true;
         if (STRING_COMPRESSION_ENABLED) {
             // For the compression purposes (save the characters as 8-bit if all characters
@@ -614,6 +761,14 @@
      *             string.
      */
     // BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+    /*
+    public char charAt(int index) {
+        if ((index < 0) || (index >= value.length)) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        return value[index];
+    }
+    */
     @FastNative
     public native char charAt(int index);
     // END Android-changed: Replace with implementation in runtime to access chars (see above).
@@ -742,6 +897,7 @@
      */
     void getChars(char dst[], int dstBegin) {
         // Android-changed: Replace arraycopy with native call since chars are managed by runtime.
+        // System.arraycopy(value, 0, dst, dstBegin, value.length);
         getCharsNoCheck(0, length(), dst, dstBegin);
     }
 
@@ -777,6 +933,18 @@
      */
     public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
         // BEGIN Android-changed: Implement in terms of length() and native getCharsNoCheck method.
+        /*
+        if (srcBegin < 0) {
+            throw new StringIndexOutOfBoundsException(srcBegin);
+        }
+        if (srcEnd > value.length) {
+            throw new StringIndexOutOfBoundsException(srcEnd);
+        }
+        if (srcBegin > srcEnd) {
+            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
+        }
+        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
+        */
         if (dst == null) {
             throw new NullPointerException("dst == null");
         }
@@ -934,8 +1102,10 @@
      */
     public byte[] getBytes(Charset charset) {
         // BEGIN Android-changed: Skip StringCoding optimization that needs access to java chars.
-        // if (charset == null) throw new NullPointerException();
-        // return StringCoding.encode(charset, value, 0, value.length);
+        /*
+        if (charset == null) throw new NullPointerException();
+        return StringCoding.encode(charset, value, 0, value.length);
+        */
         if (charset == null) {
             throw new NullPointerException("charset == null");
         }
@@ -1168,6 +1338,26 @@
      *          lexicographically greater than the string argument.
      */
     // BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+    /*
+    public int compareTo(String anotherString) {
+        int len1 = value.length;
+        int len2 = anotherString.value.length;
+        int lim = Math.min(len1, len2);
+        char v1[] = value;
+        char v2[] = anotherString.value;
+
+        int k = 0;
+        while (k < lim) {
+            char c1 = v1[k];
+            char c2 = v2[k];
+            if (c1 != c2) {
+                return c1 - c2;
+            }
+            k++;
+        }
+        return len1 - len2;
+    }
+    */
     @FastNative
     public native int compareTo(String anotherString);
     // END Android-changed: Replace with implementation in runtime to access chars (see above).
@@ -1708,6 +1898,8 @@
      */
     public int indexOf(String str, int fromIndex) {
         // Android-changed: Delegate to the static indexOf method below.
+        // return indexOf(value, 0, value.length,
+        //         str.value, 0, str.value.length, fromIndex);
         return indexOf(this, str, fromIndex);
     }
 
@@ -1865,6 +2057,8 @@
      */
     public int lastIndexOf(String str, int fromIndex) {
         // Android-changed: Change parameters to static lastIndexOf to match new signature below.
+        // return lastIndexOf(value, 0, value.length,
+        //         str.value, 0, str.value.length, fromIndex);
         return lastIndexOf(this, str, fromIndex);
     }
 
@@ -2027,6 +2221,7 @@
             throw new StringIndexOutOfBoundsException(this, beginIndex);
         }
         // Android-changed: Use native fastSubstring instead of String constructor.
+        // return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
         return (beginIndex == 0) ? this : fastSubstring(beginIndex, subLen);
     }
 
@@ -2066,6 +2261,7 @@
 
         // Android-changed: Use native fastSubstring instead of String constructor.
         return ((beginIndex == 0) && (endIndex == length())) ? this
+        //         : new String(value, beginIndex, subLen);
                 : fastSubstring(beginIndex, subLen);
     }
 
@@ -2128,6 +2324,18 @@
      *          characters followed by the string argument's characters.
      */
     // BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+    /*
+    public String concat(String str) {
+        int otherLen = str.length();
+        if (otherLen == 0) {
+            return this;
+        }
+        int len = value.length;
+        char buf[] = Arrays.copyOf(value, len + otherLen);
+        str.getChars(buf, len);
+        return new String(buf, true);
+    }
+    */
     @FastNative
     public native String concat(String str);
     // END Android-changed: Replace with implementation in runtime to access chars (see above).
@@ -2164,6 +2372,29 @@
     public String replace(char oldChar, char newChar) {
         // BEGIN Android-changed: Replace with implementation using native doReplace method.
         if (oldChar != newChar) {
+            /*
+            int len = value.length;
+            int i = -1;
+            char[] val = value; /* avoid getfield opcode *
+
+            while (++i < len) {
+                if (val[i] == oldChar) {
+                    break;
+                }
+            }
+            if (i < len) {
+                char buf[] = new char[len];
+                for (int j = 0; j < i; j++) {
+                    buf[j] = val[j];
+                }
+                while (i < len) {
+                    char c = val[i];
+                    buf[i] = (c == oldChar) ? newChar : c;
+                    i++;
+                }
+                return new String(buf, true);
+            }
+            */
             final int len = length();
             for (int i = 0; i < len; ++i) {
                 if (charAt(i) == oldChar) {
@@ -2328,6 +2559,10 @@
      */
     public String replace(CharSequence target, CharSequence replacement) {
         // BEGIN Android-changed: Replace regex-based implementation with a bespoke one.
+        /*
+        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
+                this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
+        */
         if (target == null) {
             throw new NullPointerException("target == null");
         }
@@ -2475,6 +2710,58 @@
     public String[] split(String regex, int limit) {
         // BEGIN Android-changed: Replace custom fast-path with use of new Pattern.fastSplit method.
         // Try fast splitting without allocating Pattern object
+        /*
+        /* fastpath if the regex is a
+         (1)one-char String and this character is not one of the
+            RegEx's meta characters ".$|()[{^?*+\\", or
+         (2)two-char String and the first char is the backslash and
+            the second is not the ascii digit or ascii letter.
+         *
+        char ch = 0;
+        if (((regex.value.length == 1 &&
+             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
+             (regex.length() == 2 &&
+              regex.charAt(0) == '\\' &&
+              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
+              ((ch-'a')|('z'-ch)) < 0 &&
+              ((ch-'A')|('Z'-ch)) < 0)) &&
+            (ch < Character.MIN_HIGH_SURROGATE ||
+             ch > Character.MAX_LOW_SURROGATE))
+        {
+            int off = 0;
+            int next = 0;
+            boolean limited = limit > 0;
+            ArrayList<String> list = new ArrayList<>();
+            while ((next = indexOf(ch, off)) != -1) {
+                if (!limited || list.size() < limit - 1) {
+                    list.add(substring(off, next));
+                    off = next + 1;
+                } else {    // last one
+                    //assert (list.size() == limit - 1);
+                    list.add(substring(off, value.length));
+                    off = value.length;
+                    break;
+                }
+            }
+            // If no match was found, return this
+            if (off == 0)
+                return new String[]{this};
+
+            // Add remaining segment
+            if (!limited || list.size() < limit)
+                list.add(substring(off, value.length));
+
+            // Construct result
+            int resultSize = list.size();
+            if (limit == 0) {
+                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
+                    resultSize--;
+                }
+            }
+            String[] result = new String[resultSize];
+            return list.subList(0, resultSize).toArray(result);
+        }
+        */
         String[] fast = Pattern.fastSplit(regex, this, limit);
         if (fast != null) {
             return fast;
@@ -2662,8 +2949,97 @@
      * @since   1.1
      */
     public String toLowerCase(Locale locale) {
-        // Android-changed: Replace custom code with call to new CaseMapper class.
+        // BEGIN Android-changed: Replace custom code with call to new CaseMapper class.
+        /*
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+
+        int firstUpper;
+        final int len = value.length;
+
+        /* Now check if there are any characters that need to be changed. *
+        scan: {
+            for (firstUpper = 0 ; firstUpper < len; ) {
+                char c = value[firstUpper];
+                if ((c >= Character.MIN_HIGH_SURROGATE)
+                        && (c <= Character.MAX_HIGH_SURROGATE)) {
+                    int supplChar = codePointAt(firstUpper);
+                    if (supplChar != Character.toLowerCase(supplChar)) {
+                        break scan;
+                    }
+                    firstUpper += Character.charCount(supplChar);
+                } else {
+                    if (c != Character.toLowerCase(c)) {
+                        break scan;
+                    }
+                    firstUpper++;
+                }
+            }
+            return this;
+        }
+
+        char[] result = new char[len];
+        int resultOffset = 0;  /* result may grow, so i+resultOffset
+                                * is the write location in result *
+
+        /* Just copy the first few lowerCase characters. *
+        System.arraycopy(value, 0, result, 0, firstUpper);
+
+        String lang = locale.getLanguage();
+        boolean localeDependent =
+                (lang == "tr" || lang == "az" || lang == "lt");
+        char[] lowerCharArray;
+        int lowerChar;
+        int srcChar;
+        int srcCount;
+        for (int i = firstUpper; i < len; i += srcCount) {
+            srcChar = (int)value[i];
+            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE
+                    && (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
+                srcChar = codePointAt(i);
+                srcCount = Character.charCount(srcChar);
+            } else {
+                srcCount = 1;
+            }
+            if (localeDependent ||
+                srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
+                srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
+                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
+            } else {
+                lowerChar = Character.toLowerCase(srcChar);
+            }
+            if ((lowerChar == Character.ERROR)
+                    || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
+                if (lowerChar == Character.ERROR) {
+                    lowerCharArray =
+                            ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
+                } else if (srcCount == 2) {
+                    resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
+                    continue;
+                } else {
+                    lowerCharArray = Character.toChars(lowerChar);
+                }
+
+                /* Grow result if needed *
+                int mapLen = lowerCharArray.length;
+                if (mapLen > srcCount) {
+                    char[] result2 = new char[result.length + mapLen - srcCount];
+                    System.arraycopy(result, 0, result2, 0, i + resultOffset);
+                    result = result2;
+                }
+                for (int x = 0; x < mapLen; ++x) {
+                    result[i + resultOffset + x] = lowerCharArray[x];
+                }
+                resultOffset += (mapLen - srcCount);
+            } else {
+                result[i + resultOffset] = (char)lowerChar;
+            }
+        }
+        return new String(result, 0, len + resultOffset);
+        */
         return CaseMapper.toLowerCase(locale, this);
+        // END Android-changed: Replace custom code with call to new CaseMapper class.
     }
 
     /**
@@ -2738,8 +3114,100 @@
      * @since   1.1
      */
     public String toUpperCase(Locale locale) {
-        // Android-changed: Replace custom code with call to new CaseMapper class.
+        // BEGIN Android-changed: Replace custom code with call to new CaseMapper class.
+        /*
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+
+        int firstLower;
+        final int len = value.length;
+
+        /* Now check if there are any characters that need to be changed. *
+        scan: {
+            for (firstLower = 0 ; firstLower < len; ) {
+                int c = (int)value[firstLower];
+                int srcCount;
+                if ((c >= Character.MIN_HIGH_SURROGATE)
+                        && (c <= Character.MAX_HIGH_SURROGATE)) {
+                    c = codePointAt(firstLower);
+                    srcCount = Character.charCount(c);
+                } else {
+                    srcCount = 1;
+                }
+                int upperCaseChar = Character.toUpperCaseEx(c);
+                if ((upperCaseChar == Character.ERROR)
+                        || (c != upperCaseChar)) {
+                    break scan;
+                }
+                firstLower += srcCount;
+            }
+            return this;
+        }
+
+        /* result may grow, so i+resultOffset is the write location in result *
+        int resultOffset = 0;
+        char[] result = new char[len]; /* may grow *
+
+        /* Just copy the first few upperCase characters. *
+        System.arraycopy(value, 0, result, 0, firstLower);
+
+        String lang = locale.getLanguage();
+        boolean localeDependent =
+                (lang == "tr" || lang == "az" || lang == "lt");
+        char[] upperCharArray;
+        int upperChar;
+        int srcChar;
+        int srcCount;
+        for (int i = firstLower; i < len; i += srcCount) {
+            srcChar = (int)value[i];
+            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
+                (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
+                srcChar = codePointAt(i);
+                srcCount = Character.charCount(srcChar);
+            } else {
+                srcCount = 1;
+            }
+            if (localeDependent) {
+                upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
+            } else {
+                upperChar = Character.toUpperCaseEx(srcChar);
+            }
+            if ((upperChar == Character.ERROR)
+                    || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
+                if (upperChar == Character.ERROR) {
+                    if (localeDependent) {
+                        upperCharArray =
+                                ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
+                    } else {
+                        upperCharArray = Character.toUpperCaseCharArray(srcChar);
+                    }
+                } else if (srcCount == 2) {
+                    resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
+                    continue;
+                } else {
+                    upperCharArray = Character.toChars(upperChar);
+                }
+
+                /* Grow result if needed *
+                int mapLen = upperCharArray.length;
+                if (mapLen > srcCount) {
+                    char[] result2 = new char[result.length + mapLen - srcCount];
+                    System.arraycopy(result, 0, result2, 0, i + resultOffset);
+                    result = result2;
+                }
+                for (int x = 0; x < mapLen; ++x) {
+                    result[i + resultOffset + x] = upperCharArray[x];
+                }
+                resultOffset += (mapLen - srcCount);
+            } else {
+                result[i + resultOffset] = (char)upperChar;
+            }
+        }
+        return new String(result, 0, len + resultOffset);
+        */
         return CaseMapper.toUpperCase(locale, this, length());
+        // END Android-changed: Replace custom code with call to new CaseMapper class.
     }
 
     /**
@@ -2826,6 +3294,14 @@
      *          the character sequence represented by this string.
      */
     // BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+    /*
+    public char[] toCharArray() {
+        // Cannot use Arrays.copyOf because of class initialization order issues
+        char result[] = new char[value.length];
+        System.arraycopy(value, 0, result, 0, value.length);
+        return result;
+    }
+    */
     @FastNative
     public native char[] toCharArray();
     // END Android-changed: Replace with implementation in runtime to access chars (see above).
@@ -3097,8 +3573,7 @@
      * @return  a string that has the same contents as this string, but is
      *          guaranteed to be from a pool of unique strings.
      */
-    // BEGIN Android-changed: Annotate native method as @FastNative.
+    // Android-added: Annotate native method as @FastNative.
     @FastNative
-    // END Android-changed: Annotate native method as @FastNative.
     public native String intern();
 }
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index e22c3aa..3263383 100644
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -42,6 +42,7 @@
 import sun.reflect.CallerSensitive;
 import dalvik.system.VMStack;
 import libcore.util.EmptyArray;
+import jdk.internal.HotSpotIntrinsicCandidate;
 
 
 /**
@@ -310,8 +311,7 @@
      *
      * @return  the currently executing thread.
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public static native Thread currentThread();
 
@@ -489,8 +489,7 @@
      *
      * @since 9
      */
-    // Android-removed: @HotSpotIntrinsicCandidate
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public static void onSpinWait() {}
 
     /**
@@ -2412,19 +2411,17 @@
     // concurrent code, and we can not risk accidental false sharing.
     // Hence, the fields are isolated with @Contended.
 
-    // BEGIN Android-changed: @jdk.internal.vm.annotation.Contended is not supported on Android.
     /** The current seed for a ThreadLocalRandom */
-    // @jdk.internal.vm.annotation.Contended("tlr")
+    @jdk.internal.vm.annotation.Contended("tlr")
     long threadLocalRandomSeed;
 
     /** Probe hash value; nonzero if threadLocalRandomSeed initialized */
-    // @jdk.internal.vm.annotation.Contended("tlr")
+    @jdk.internal.vm.annotation.Contended("tlr")
     int threadLocalRandomProbe;
 
     /** Secondary seed isolated from public ThreadLocalRandom sequence */
-    //  @jdk.internal.vm.annotation.Contended("tlr")
+    @jdk.internal.vm.annotation.Contended("tlr")
     int threadLocalRandomSecondarySeed;
-    // END Android-changed: @jdk.internal.vm.annotation.Contended is not supported on Android.
 
     /* Some private helper methods */
     private native void setPriority0(int newPriority);
diff --git a/ojluni/src/main/java/java/lang/invoke/VarHandle.java b/ojluni/src/main/java/java/lang/invoke/VarHandle.java
index 40473f0..0febea9 100644
--- a/ojluni/src/main/java/java/lang/invoke/VarHandle.java
+++ b/ojluni/src/main/java/java/lang/invoke/VarHandle.java
@@ -26,6 +26,7 @@
 package java.lang.invoke;
 
 import dalvik.system.VMRuntime;
+import jdk.internal.HotSpotIntrinsicCandidate;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -490,8 +491,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object get(Object... args);
 
     /**
@@ -517,8 +517,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     void set(Object... args);
 
 
@@ -550,8 +549,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getVolatile(Object... args);
 
     /**
@@ -581,8 +579,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     void setVolatile(Object... args);
 
 
@@ -612,8 +609,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getOpaque(Object... args);
 
     /**
@@ -640,8 +636,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     void setOpaque(Object... args);
 
 
@@ -678,8 +673,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAcquire(Object... args);
 
     /**
@@ -710,8 +704,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     void setRelease(Object... args);
 
 
@@ -747,8 +740,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     boolean compareAndSet(Object... args);
 
     /**
@@ -783,8 +775,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object compareAndExchange(Object... args);
 
     /**
@@ -819,8 +810,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object compareAndExchangeAcquire(Object... args);
 
     /**
@@ -855,8 +845,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object compareAndExchangeRelease(Object... args);
 
     // Weak (spurious failures allowed)
@@ -895,8 +884,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     boolean weakCompareAndSetPlain(Object... args);
 
     /**
@@ -933,8 +921,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     boolean weakCompareAndSet(Object... args);
 
     /**
@@ -972,8 +959,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     boolean weakCompareAndSetAcquire(Object... args);
 
     /**
@@ -1011,8 +997,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     boolean weakCompareAndSetRelease(Object... args);
 
     /**
@@ -1045,8 +1030,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndSet(Object... args);
 
     /**
@@ -1079,8 +1063,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndSetAcquire(Object... args);
 
     /**
@@ -1113,8 +1096,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndSetRelease(Object... args);
 
     // Primitive adders
@@ -1150,8 +1132,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndAdd(Object... args);
 
     /**
@@ -1184,8 +1165,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndAddAcquire(Object... args);
 
     /**
@@ -1218,8 +1198,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndAddRelease(Object... args);
 
 
@@ -1260,8 +1239,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseOr(Object... args);
 
     /**
@@ -1298,8 +1276,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseOrAcquire(Object... args);
 
     /**
@@ -1336,8 +1313,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseOrRelease(Object... args);
 
     /**
@@ -1374,8 +1350,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseAnd(Object... args);
 
     /**
@@ -1412,8 +1387,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseAndAcquire(Object... args);
 
     /**
@@ -1450,8 +1424,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseAndRelease(Object... args);
 
     /**
@@ -1488,8 +1461,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseXor(Object... args);
 
     /**
@@ -1526,8 +1498,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseXorAcquire(Object... args);
 
     /**
@@ -1564,8 +1535,7 @@
      */
     public final native
     @MethodHandle.PolymorphicSignature
-    // Android-removed: unsupported annotation.
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     Object getAndBitwiseXorRelease(Object... args);
 
 
diff --git a/ojluni/src/main/java/java/math/BigDecimal.java b/ojluni/src/main/java/java/math/BigDecimal.java
index 9e012a6..25d8f2b 100644
--- a/ojluni/src/main/java/java/math/BigDecimal.java
+++ b/ojluni/src/main/java/java/math/BigDecimal.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -40,7 +40,7 @@
  * decimal point.  If negative, the unscaled value of the number is
  * multiplied by ten to the power of the negation of the scale.  The
  * value of the number represented by the {@code BigDecimal} is
- * therefore <tt>(unscaledValue &times; 10<sup>-scale</sup>)</tt>.
+ * therefore <code>(unscaledValue &times; 10<sup>-scale</sup>)</code>.
  *
  * <p>The {@code BigDecimal} class provides operations for
  * arithmetic, scale manipulation, rounding, comparison, hashing, and
@@ -55,7 +55,7 @@
  * object to the operation.  In either case, eight <em>rounding
  * modes</em> are provided for the control of rounding.  Using the
  * integer fields in this class (such as {@link #ROUND_HALF_UP}) to
- * represent rounding mode is largely obsolete; the enumeration values
+ * represent rounding mode is deprecated; the enumeration values
  * of the {@code RoundingMode} {@code enum}, (such as {@link
  * RoundingMode#HALF_UP}) should be used instead.
  *
@@ -93,7 +93,7 @@
  * <p>In general the rounding modes and precision setting determine
  * how operations return results with a limited number of digits when
  * the exact result has more digits (perhaps infinitely many in the
- * case of division) than the number of digits returned.
+ * case of division and square root) than the number of digits returned.
  *
  * First, the
  * total number of digits to return is specified by the
@@ -120,14 +120,19 @@
  * preferred scale for representing a result.  The preferred
  * scale for each operation is listed in the table below.
  *
- * <table border>
- * <caption><b>Preferred Scales for Results of Arithmetic Operations
- * </b></caption>
- * <tr><th>Operation</th><th>Preferred Scale of Result</th></tr>
- * <tr><td>Add</td><td>max(addend.scale(), augend.scale())</td>
- * <tr><td>Subtract</td><td>max(minuend.scale(), subtrahend.scale())</td>
- * <tr><td>Multiply</td><td>multiplier.scale() + multiplicand.scale()</td>
- * <tr><td>Divide</td><td>dividend.scale() - divisor.scale()</td>
+ * <table class="striped" style="text-align:left">
+ * <caption>Preferred Scales for Results of Arithmetic Operations
+ * </caption>
+ * <thead>
+ * <tr><th scope="col">Operation</th><th scope="col">Preferred Scale of Result</th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><th scope="row">Add</th><td>max(addend.scale(), augend.scale())</td>
+ * <tr><th scope="row">Subtract</th><td>max(minuend.scale(), subtrahend.scale())</td>
+ * <tr><th scope="row">Multiply</th><td>multiplier.scale() + multiplicand.scale()</td>
+ * <tr><th scope="row">Divide</th><td>dividend.scale() - divisor.scale()</td>
+ * <tr><th scope="row">Square root</th><td>radicand.scale()/2</td>
+ * </tbody>
  * </table>
  *
  * These scales are the ones used by the methods which return exact
@@ -195,18 +200,19 @@
  * {@code BigDecimal} value; for example [19, 2] is the
  * {@code BigDecimal} numerically equal to 0.19 having a scale of 2.
  *
- * <p>Note: care should be exercised if {@code BigDecimal} objects
- * are used as keys in a {@link java.util.SortedMap SortedMap} or
- * elements in a {@link java.util.SortedSet SortedSet} since
- * {@code BigDecimal}'s <i>natural ordering</i> is <i>inconsistent
- * with equals</i>.  See {@link Comparable}, {@link
- * java.util.SortedMap} or {@link java.util.SortedSet} for more
- * information.
  *
  * <p>All methods and constructors for this class throw
  * {@code NullPointerException} when passed a {@code null} object
  * reference for any input parameter.
  *
+ * @apiNote Care should be exercised if {@code BigDecimal} objects
+ * are used as keys in a {@link java.util.SortedMap SortedMap} or
+ * elements in a {@link java.util.SortedSet SortedSet} since
+ * {@code BigDecimal}'s <i>natural ordering</i> is <em>inconsistent
+ * with equals</em>.  See {@link Comparable}, {@link
+ * java.util.SortedMap} or {@link java.util.SortedSet} for more
+ * information.
+ *
  * @see     BigInteger
  * @see     MathContext
  * @see     RoundingMode
@@ -216,6 +222,7 @@
  * @author  Mike Cowlishaw
  * @author  Joseph D. Darcy
  * @author  Sergey V. Kuksenko
+ * @since 1.1
  */
 public class BigDecimal extends Number implements Comparable<BigDecimal> {
     /**
@@ -283,10 +290,10 @@
     };
 
     // Cache of common small BigDecimal values.
-    private static final BigDecimal zeroThroughTen[] = {
+    private static final BigDecimal ZERO_THROUGH_TEN[] = {
         new BigDecimal(BigInteger.ZERO,       0,  0, 1),
         new BigDecimal(BigInteger.ONE,        1,  0, 1),
-        new BigDecimal(BigInteger.valueOf(2), 2,  0, 1),
+        new BigDecimal(BigInteger.TWO,        2,  0, 1),
         new BigDecimal(BigInteger.valueOf(3), 3,  0, 1),
         new BigDecimal(BigInteger.valueOf(4), 4,  0, 1),
         new BigDecimal(BigInteger.valueOf(5), 5,  0, 1),
@@ -299,7 +306,7 @@
 
     // Cache of zero scaled by 0 - 15
     private static final BigDecimal[] ZERO_SCALED_BY = {
-        zeroThroughTen[0],
+        ZERO_THROUGH_TEN[0],
         new BigDecimal(BigInteger.ZERO, 0, 1, 1),
         new BigDecimal(BigInteger.ZERO, 0, 2, 1),
         new BigDecimal(BigInteger.ZERO, 0, 3, 1),
@@ -328,7 +335,7 @@
      * @since  1.5
      */
     public static final BigDecimal ZERO =
-        zeroThroughTen[0];
+        ZERO_THROUGH_TEN[0];
 
     /**
      * The value 1, with a scale of 0.
@@ -336,7 +343,7 @@
      * @since  1.5
      */
     public static final BigDecimal ONE =
-        zeroThroughTen[1];
+        ZERO_THROUGH_TEN[1];
 
     /**
      * The value 10, with a scale of 0.
@@ -344,7 +351,17 @@
      * @since  1.5
      */
     public static final BigDecimal TEN =
-        zeroThroughTen[10];
+        ZERO_THROUGH_TEN[10];
+
+    /**
+     * The value 0.1, with a scale of 1.
+     */
+    private static final BigDecimal ONE_TENTH = valueOf(1L, 1);
+
+    /**
+     * The value 0.5, with a scale of 1.
+     */
+    private static final BigDecimal ONE_HALF = valueOf(5L, 1);
 
     // Constructors
 
@@ -366,10 +383,10 @@
      * same sequence of characters as the {@link #BigDecimal(String)}
      * constructor, while allowing a sub-array to be specified.
      *
-     * <p>Note that if the sequence of characters is already available
+     * @implNote If the sequence of characters is already available
      * within a character array, using this constructor is faster than
      * converting the {@code char} array to string and using the
-     * {@code BigDecimal(String)} constructor .
+     * {@code BigDecimal(String)} constructor.
      *
      * @param  in {@code char} array that is the source of characters.
      * @param  offset first character in the array to inspect.
@@ -390,14 +407,14 @@
      * constructor, while allowing a sub-array to be specified and
      * with rounding according to the context settings.
      *
-     * <p>Note that if the sequence of characters is already available
+     * @implNote If the sequence of characters is already available
      * within a character array, using this constructor is faster than
      * converting the {@code char} array to string and using the
-     * {@code BigDecimal(String)} constructor .
+     * {@code BigDecimal(String)} constructor.
      *
      * @param  in {@code char} array that is the source of characters.
      * @param  offset first character in the array to inspect.
-     * @param  len number of characters to consider..
+     * @param  len number of characters to consider.
      * @param  mc the context to use.
      * @throws ArithmeticException if the result is inexact but the
      *         rounding mode is {@code UNNECESSARY}.
@@ -407,12 +424,9 @@
      * @since  1.5
      */
     public BigDecimal(char[] in, int offset, int len, MathContext mc) {
-        // protect against huge length, negative values, and integer overflow
-        if ((in.length | len | offset) < 0 || len > in.length - offset) {
-            throw new NumberFormatException
-                ("Bad offset or len arguments for char[] input.");
-        }
-
+        // protect against huge length.
+        if (offset + len > in.length || offset < 0)
+            throw new NumberFormatException("Bad offset or len arguments for char[] input.");
         // This is the primary string to BigDecimal constructor; all
         // incoming strings end up here; it uses explicit (inline)
         // parsing for speed and generates at most one intermediate
@@ -469,7 +483,8 @@
                     } else if (c == '.') {   // have dot
                         // have dot
                         if (dot) // two dots
-                            throw new NumberFormatException();
+                            throw new NumberFormatException("Character array"
+                                + " contains more than one decimal point.");
                         dot = true;
                     } else if (Character.isDigit(c)) { // slow path
                         int digit = Character.digit(c, 10);
@@ -491,14 +506,16 @@
                         exp = parseExp(in, offset, len);
                         // Next test is required for backwards compatibility
                         if ((int) exp != exp) // overflow
-                            throw new NumberFormatException();
+                            throw new NumberFormatException("Exponent overflow.");
                         break; // [saves a test]
                     } else {
-                        throw new NumberFormatException();
+                        throw new NumberFormatException("Character " + c
+                            + " is neither a decimal digit number, decimal point, nor"
+                            + " \"e\" notation exponential mark.");
                     }
                 }
                 if (prec == 0) // no digits found
-                    throw new NumberFormatException();
+                    throw new NumberFormatException("No digits found.");
                 // Adjust scale if exp is not zero.
                 if (exp != 0) { // had significant exponent
                     scl = adjustScale(scl, exp);
@@ -544,22 +561,24 @@
                     if (c == '.') {
                         // have dot
                         if (dot) // two dots
-                            throw new NumberFormatException();
+                            throw new NumberFormatException("Character array"
+                                + " contains more than one decimal point.");
                         dot = true;
                         continue;
                     }
                     // exponent expected
                     if ((c != 'e') && (c != 'E'))
-                        throw new NumberFormatException();
+                        throw new NumberFormatException("Character array"
+                            + " is missing \"e\" notation exponential mark.");
                     exp = parseExp(in, offset, len);
                     // Next test is required for backwards compatibility
                     if ((int) exp != exp) // overflow
-                        throw new NumberFormatException();
+                        throw new NumberFormatException("Exponent overflow.");
                     break; // [saves a test]
                 }
                 // here when no characters left
                 if (prec == 0) // no digits found
-                    throw new NumberFormatException();
+                    throw new NumberFormatException("No digits found.");
                 // Adjust scale if exp is not zero.
                 if (exp != 0) { // had significant exponent
                     scl = adjustScale(scl, exp);
@@ -595,10 +614,10 @@
                     }
                 }
             }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            throw new NumberFormatException();
-        } catch (NegativeArraySizeException e) {
-            throw new NumberFormatException();
+        } catch (ArrayIndexOutOfBoundsException | NegativeArraySizeException e) {
+            NumberFormatException nfe = new NumberFormatException();
+            nfe.initCause(e);
+            throw nfe;
         }
         this.scale = scl;
         this.precision = prec;
@@ -630,7 +649,7 @@
             len--;
         }
         if (len <= 0) // no exponent digits
-            throw new NumberFormatException();
+            throw new NumberFormatException("No exponent digits.");
         // skip leading zeros in the exponent
         while (len > 10 && (c=='0' || (Character.digit(c, 10) == 0))) {
             offset++;
@@ -638,7 +657,7 @@
             len--;
         }
         if (len > 10) // too many nonzero exponent digits
-            throw new NumberFormatException();
+            throw new NumberFormatException("Too many nonzero exponent digits.");
         // c now holds first digit of exponent
         for (;; len--) {
             int v;
@@ -647,7 +666,7 @@
             } else {
                 v = Character.digit(c, 10);
                 if (v < 0) // not a digit
-                    throw new NumberFormatException();
+                    throw new NumberFormatException("Not a digit.");
             }
             exp = exp * 10 + v;
             if (len == 1)
@@ -666,10 +685,10 @@
      * same sequence of characters as the {@link #BigDecimal(String)}
      * constructor.
      *
-     * <p>Note that if the sequence of characters is already available
+     * @implNote If the sequence of characters is already available
      * as a character array, using this constructor is faster than
      * converting the {@code char} array to string and using the
-     * {@code BigDecimal(String)} constructor .
+     * {@code BigDecimal(String)} constructor.
      *
      * @param in {@code char} array that is the source of characters.
      * @throws NumberFormatException if {@code in} is not a valid
@@ -687,10 +706,10 @@
      * constructor and with rounding according to the context
      * settings.
      *
-     * <p>Note that if the sequence of characters is already available
+     * @implNote If the sequence of characters is already available
      * as a character array, using this constructor is faster than
      * converting the {@code char} array to string and using the
-     * {@code BigDecimal(String)} constructor .
+     * {@code BigDecimal(String)} constructor.
      *
      * @param  in {@code char} array that is the source of characters.
      * @param  mc the context to use.
@@ -707,8 +726,8 @@
     /**
      * Translates the string representation of a {@code BigDecimal}
      * into a {@code BigDecimal}.  The string representation consists
-     * of an optional sign, {@code '+'} (<tt> '&#92;u002B'</tt>) or
-     * {@code '-'} (<tt>'&#92;u002D'</tt>), followed by a sequence of
+     * of an optional sign, {@code '+'} (<code> '&#92;u002B'</code>) or
+     * {@code '-'} (<code>'&#92;u002D'</code>), followed by a sequence of
      * zero or more decimal digits ("the integer"), optionally
      * followed by a fraction, optionally followed by an exponent.
      *
@@ -719,7 +738,7 @@
      * <i>significand</i>.
      *
      * <p>The exponent consists of the character {@code 'e'}
-     * (<tt>'&#92;u0065'</tt>) or {@code 'E'} (<tt>'&#92;u0045'</tt>)
+     * (<code>'&#92;u0065'</code>) or {@code 'E'} (<code>'&#92;u0045'</code>)
      * followed by one or more decimal digits.  The value of the
      * exponent must lie between -{@link Integer#MAX_VALUE} ({@link
      * Integer#MIN_VALUE}+1) and {@link Integer#MAX_VALUE}, inclusive.
@@ -792,7 +811,7 @@
      * "-0"           [0,0]
      * </pre>
      *
-     * <p>Note: For values other than {@code float} and
+     * @apiNote For values other than {@code float} and
      * {@code double} NaN and &plusmn;Infinity, this constructor is
      * compatible with the values returned by {@link Float#toString}
      * and {@link Double#toString}.  This is generally the preferred
@@ -832,7 +851,7 @@
      * is the exact decimal representation of the {@code double}'s
      * binary floating-point value.  The scale of the returned
      * {@code BigDecimal} is the smallest value such that
-     * <tt>(10<sup>scale</sup> &times; val)</tt> is an integer.
+     * <code>(10<sup>scale</sup> &times; val)</code> is an integer.
      * <p>
      * <b>Notes:</b>
      * <ol>
@@ -846,16 +865,16 @@
      * This is because 0.1 cannot be represented exactly as a
      * {@code double} (or, for that matter, as a binary fraction of
      * any finite length).  Thus, the value that is being passed
-     * <i>in</i> to the constructor is not exactly equal to 0.1,
+     * <em>in</em> to the constructor is not exactly equal to 0.1,
      * appearances notwithstanding.
      *
      * <li>
      * The {@code String} constructor, on the other hand, is
      * perfectly predictable: writing {@code new BigDecimal("0.1")}
-     * creates a {@code BigDecimal} which is <i>exactly</i> equal to
+     * creates a {@code BigDecimal} which is <em>exactly</em> equal to
      * 0.1, as one would expect.  Therefore, it is generally
      * recommended that the {@linkplain #BigDecimal(String)
-     * <tt>String</tt> constructor} be used in preference to this one.
+     * String constructor} be used in preference to this one.
      *
      * <li>
      * When a {@code double} must be used as a source for a
@@ -879,7 +898,7 @@
      * Translates a {@code double} into a {@code BigDecimal}, with
      * rounding according to the context settings.  The scale of the
      * {@code BigDecimal} is the smallest value such that
-     * <tt>(10<sup>scale</sup> &times; val)</tt> is an integer.
+     * <code>(10<sup>scale</sup> &times; val)</code> is an integer.
      *
      * <p>The results of this constructor can be somewhat unpredictable
      * and its use is generally not recommended; see the notes under
@@ -923,20 +942,20 @@
             significand >>= 1;
             exponent++;
         }
-        int scale = 0;
+        int scl = 0;
         // Calculate intVal and scale
-        BigInteger intVal;
+        BigInteger rb;
         long compactVal = sign * significand;
         if (exponent == 0) {
-            intVal = (compactVal == INFLATED) ? INFLATED_BIGINT : null;
+            rb = (compactVal == INFLATED) ? INFLATED_BIGINT : null;
         } else {
             if (exponent < 0) {
-                intVal = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal);
-                scale = -exponent;
+                rb = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal);
+                scl = -exponent;
             } else { //  (exponent > 0)
-                intVal = BigInteger.valueOf(2).pow(exponent).multiply(compactVal);
+                rb = BigInteger.TWO.pow(exponent).multiply(compactVal);
             }
-            compactVal = compactValFor(intVal);
+            compactVal = compactValFor(rb);
         }
         int prec = 0;
         int mcp = mc.precision;
@@ -944,16 +963,16 @@
             int mode = mc.roundingMode.oldMode;
             int drop;
             if (compactVal == INFLATED) {
-                prec = bigDigitLength(intVal);
+                prec = bigDigitLength(rb);
                 drop = prec - mcp;
                 while (drop > 0) {
-                    scale = checkScaleNonZero((long) scale - drop);
-                    intVal = divideAndRoundByTenPow(intVal, drop, mode);
-                    compactVal = compactValFor(intVal);
+                    scl = checkScaleNonZero((long) scl - drop);
+                    rb = divideAndRoundByTenPow(rb, drop, mode);
+                    compactVal = compactValFor(rb);
                     if (compactVal != INFLATED) {
                         break;
                     }
-                    prec = bigDigitLength(intVal);
+                    prec = bigDigitLength(rb);
                     drop = prec - mcp;
                 }
             }
@@ -961,17 +980,17 @@
                 prec = longDigitLength(compactVal);
                 drop = prec - mcp;
                 while (drop > 0) {
-                    scale = checkScaleNonZero((long) scale - drop);
+                    scl = checkScaleNonZero((long) scl - drop);
                     compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
                     prec = longDigitLength(compactVal);
                     drop = prec - mcp;
                 }
-                intVal = null;
+                rb = null;
             }
         }
-        this.intVal = intVal;
+        this.intVal = rb;
         this.intCompact = compactVal;
-        this.scale = scale;
+        this.scale = scl;
         this.precision = prec;
     }
 
@@ -1008,7 +1027,7 @@
      * Translates a {@code BigInteger} unscaled value and an
      * {@code int} scale into a {@code BigDecimal}.  The value of
      * the {@code BigDecimal} is
-     * <tt>(unscaledVal &times; 10<sup>-scale</sup>)</tt>.
+     * <code>(unscaledVal &times; 10<sup>-scale</sup>)</code>.
      *
      * @param unscaledVal unscaled value of the {@code BigDecimal}.
      * @param scale scale of the {@code BigDecimal}.
@@ -1024,8 +1043,8 @@
      * Translates a {@code BigInteger} unscaled value and an
      * {@code int} scale into a {@code BigDecimal}, with rounding
      * according to the context settings.  The value of the
-     * {@code BigDecimal} is <tt>(unscaledVal &times;
-     * 10<sup>-scale</sup>)</tt>, rounded according to the
+     * {@code BigDecimal} is <code>(unscaledVal &times;
+     * 10<sup>-scale</sup>)</code>, rounded according to the
      * {@code precision} and rounding mode settings.
      *
      * @param  unscaledVal unscaled value of the {@code BigDecimal}.
@@ -1101,13 +1120,13 @@
     public BigDecimal(int val, MathContext mc) {
         int mcp = mc.precision;
         long compactVal = val;
-        int scale = 0;
+        int scl = 0;
         int prec = 0;
         if (mcp > 0) { // do rounding
             prec = longDigitLength(compactVal);
             int drop = prec - mcp; // drop can't be more than 18
             while (drop > 0) {
-                scale = checkScaleNonZero((long) scale - drop);
+                scl = checkScaleNonZero((long) scl - drop);
                 compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
                 prec = longDigitLength(compactVal);
                 drop = prec - mcp;
@@ -1115,7 +1134,7 @@
         }
         this.intVal = null;
         this.intCompact = compactVal;
-        this.scale = scale;
+        this.scale = scl;
         this.precision = prec;
     }
 
@@ -1147,20 +1166,20 @@
         int mcp = mc.precision;
         int mode = mc.roundingMode.oldMode;
         int prec = 0;
-        int scale = 0;
-        BigInteger intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
+        int scl = 0;
+        BigInteger rb = (val == INFLATED) ? INFLATED_BIGINT : null;
         if (mcp > 0) { // do rounding
             if (val == INFLATED) {
                 prec = 19;
                 int drop = prec - mcp;
                 while (drop > 0) {
-                    scale = checkScaleNonZero((long) scale - drop);
-                    intVal = divideAndRoundByTenPow(intVal, drop, mode);
-                    val = compactValFor(intVal);
+                    scl = checkScaleNonZero((long) scl - drop);
+                    rb = divideAndRoundByTenPow(rb, drop, mode);
+                    val = compactValFor(rb);
                     if (val != INFLATED) {
                         break;
                     }
-                    prec = bigDigitLength(intVal);
+                    prec = bigDigitLength(rb);
                     drop = prec - mcp;
                 }
             }
@@ -1168,17 +1187,17 @@
                 prec = longDigitLength(val);
                 int drop = prec - mcp;
                 while (drop > 0) {
-                    scale = checkScaleNonZero((long) scale - drop);
+                    scl = checkScaleNonZero((long) scl - drop);
                     val = divideAndRound(val, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
                     prec = longDigitLength(val);
                     drop = prec - mcp;
                 }
-                intVal = null;
+                rb = null;
             }
         }
-        this.intVal = intVal;
+        this.intVal = rb;
         this.intCompact = val;
-        this.scale = scale;
+        this.scale = scl;
         this.precision = prec;
     }
 
@@ -1186,15 +1205,16 @@
 
     /**
      * Translates a {@code long} unscaled value and an
-     * {@code int} scale into a {@code BigDecimal}.  This
-     * {@literal "static factory method"} is provided in preference to
-     * a ({@code long}, {@code int}) constructor because it
-     * allows for reuse of frequently used {@code BigDecimal} values..
+     * {@code int} scale into a {@code BigDecimal}.
+     *
+     * @apiNote This static factory method is provided in preference
+     * to a ({@code long}, {@code int}) constructor because it allows
+     * for reuse of frequently used {@code BigDecimal} values.
      *
      * @param unscaledVal unscaled value of the {@code BigDecimal}.
      * @param scale scale of the {@code BigDecimal}.
      * @return a {@code BigDecimal} whose value is
-     *         <tt>(unscaledVal &times; 10<sup>-scale</sup>)</tt>.
+     *         <code>(unscaledVal &times; 10<sup>-scale</sup>)</code>.
      */
     public static BigDecimal valueOf(long unscaledVal, int scale) {
         if (scale == 0)
@@ -1209,25 +1229,26 @@
 
     /**
      * Translates a {@code long} value into a {@code BigDecimal}
-     * with a scale of zero.  This {@literal "static factory method"}
-     * is provided in preference to a ({@code long}) constructor
-     * because it allows for reuse of frequently used
-     * {@code BigDecimal} values.
+     * with a scale of zero.
+     *
+     * @apiNote This static factory method is provided in preference
+     * to a ({@code long}) constructor because it allows for reuse of
+     * frequently used {@code BigDecimal} values.
      *
      * @param val value of the {@code BigDecimal}.
      * @return a {@code BigDecimal} whose value is {@code val}.
      */
     public static BigDecimal valueOf(long val) {
-        if (val >= 0 && val < zeroThroughTen.length)
-            return zeroThroughTen[(int)val];
+        if (val >= 0 && val < ZERO_THROUGH_TEN.length)
+            return ZERO_THROUGH_TEN[(int)val];
         else if (val != INFLATED)
             return new BigDecimal(null, val, 0, 0);
         return new BigDecimal(INFLATED_BIGINT, val, 0, 0);
     }
 
     static BigDecimal valueOf(long unscaledVal, int scale, int prec) {
-        if (scale == 0 && unscaledVal >= 0 && unscaledVal < zeroThroughTen.length) {
-            return zeroThroughTen[(int) unscaledVal];
+        if (scale == 0 && unscaledVal >= 0 && unscaledVal < ZERO_THROUGH_TEN.length) {
+            return ZERO_THROUGH_TEN[(int) unscaledVal];
         } else if (unscaledVal == 0) {
             return zeroValueOf(scale);
         }
@@ -1239,8 +1260,8 @@
         long val = compactValFor(intVal);
         if (val == 0) {
             return zeroValueOf(scale);
-        } else if (scale == 0 && val >= 0 && val < zeroThroughTen.length) {
-            return zeroThroughTen[(int) val];
+        } else if (scale == 0 && val >= 0 && val < ZERO_THROUGH_TEN.length) {
+            return ZERO_THROUGH_TEN[(int) val];
         }
         return new BigDecimal(intVal, val, scale, prec);
     }
@@ -1257,11 +1278,11 @@
      * the {@code double}'s canonical string representation provided
      * by the {@link Double#toString(double)} method.
      *
-     * <p><b>Note:</b> This is generally the preferred way to convert
-     * a {@code double} (or {@code float}) into a
-     * {@code BigDecimal}, as the value returned is equal to that
-     * resulting from constructing a {@code BigDecimal} from the
-     * result of using {@link Double#toString(double)}.
+     * @apiNote This is generally the preferred way to convert a
+     * {@code double} (or {@code float}) into a {@code BigDecimal}, as
+     * the value returned is equal to that resulting from constructing
+     * a {@code BigDecimal} from the result of using {@link
+     * Double#toString(double)}.
      *
      * @param  val {@code double} to convert to a {@code BigDecimal}.
      * @return a {@code BigDecimal} whose value is equal to or approximately
@@ -1474,8 +1495,8 @@
     }
 
     /**
-     * Returns a {@code BigDecimal} whose value is <tt>(this &times;
-     * multiplicand)</tt>, and whose scale is {@code (this.scale() +
+     * Returns a {@code BigDecimal} whose value is <code>(this &times;
+     * multiplicand)</code>, and whose scale is {@code (this.scale() +
      * multiplicand.scale())}.
      *
      * @param  multiplicand value to be multiplied by this {@code BigDecimal}.
@@ -1499,8 +1520,8 @@
     }
 
     /**
-     * Returns a {@code BigDecimal} whose value is <tt>(this &times;
-     * multiplicand)</tt>, with rounding according to the context settings.
+     * Returns a {@code BigDecimal} whose value is <code>(this &times;
+     * multiplicand)</code>, with rounding according to the context settings.
      *
      * @param  multiplicand value to be multiplied by this {@code BigDecimal}.
      * @param  mc the context to use.
@@ -1534,7 +1555,7 @@
      * be performed to generate a result with the specified scale, the
      * specified rounding mode is applied.
      *
-     * <p>The new {@link #divide(BigDecimal, int, RoundingMode)} method
+     * @deprecated The method {@link #divide(BigDecimal, int, RoundingMode)}
      * should be used in preference to this legacy method.
      *
      * @param  divisor value by which this {@code BigDecimal} is to be divided.
@@ -1556,6 +1577,7 @@
      * @see    #ROUND_HALF_EVEN
      * @see    #ROUND_UNNECESSARY
      */
+    @Deprecated(since="9")
     public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
         if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
             throw new IllegalArgumentException("Invalid rounding mode");
@@ -1600,7 +1622,7 @@
      * rounding must be performed to generate a result with the given
      * scale, the specified rounding mode is applied.
      *
-     * <p>The new {@link #divide(BigDecimal, RoundingMode)} method
+     * @deprecated The method {@link #divide(BigDecimal, RoundingMode)}
      * should be used in preference to this legacy method.
      *
      * @param  divisor value by which this {@code BigDecimal} is to be divided.
@@ -1621,6 +1643,7 @@
      * @see    #ROUND_HALF_EVEN
      * @see    #ROUND_UNNECESSARY
      */
+    @Deprecated(since="9")
     public BigDecimal divide(BigDecimal divisor, int roundingMode) {
         return this.divide(divisor, scale, roundingMode);
     }
@@ -1881,7 +1904,7 @@
      *
      * <p>The remainder is given by
      * {@code this.subtract(this.divideToIntegralValue(divisor).multiply(divisor))}.
-     * Note that this is not the modulo operation (the result can be
+     * Note that this is <em>not</em> the modulo operation (the result can be
      * negative).
      *
      * @param  divisor value by which this {@code BigDecimal} is to be divided.
@@ -1992,8 +2015,298 @@
     }
 
     /**
+     * Returns an approximation to the square root of {@code this}
+     * with rounding according to the context settings.
+     *
+     * <p>The preferred scale of the returned result is equal to
+     * {@code this.scale()/2}. The value of the returned result is
+     * always within one ulp of the exact decimal value for the
+     * precision in question.  If the rounding mode is {@link
+     * RoundingMode#HALF_UP HALF_UP}, {@link RoundingMode#HALF_DOWN
+     * HALF_DOWN}, or {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
+     * result is within one half an ulp of the exact decimal value.
+     *
+     * <p>Special case:
+     * <ul>
+     * <li> The square root of a number numerically equal to {@code
+     * ZERO} is numerically equal to {@code ZERO} with a preferred
+     * scale according to the general rule above. In particular, for
+     * {@code ZERO}, {@code ZERO.sqrt(mc).equals(ZERO)} is true with
+     * any {@code MathContext} as an argument.
+     * </ul>
+     *
+     * @param mc the context to use.
+     * @return the square root of {@code this}.
+     * @throws ArithmeticException if {@code this} is less than zero.
+     * @throws ArithmeticException if an exact result is requested
+     * ({@code mc.getPrecision()==0}) and there is no finite decimal
+     * expansion of the exact result
+     * @throws ArithmeticException if
+     * {@code (mc.getRoundingMode()==RoundingMode.UNNECESSARY}) and
+     * the exact result cannot fit in {@code mc.getPrecision()}
+     * digits.
+     * @see BigInteger#sqrt()
+     * @since  9
+     */
+    public BigDecimal sqrt(MathContext mc) {
+        int signum = signum();
+        if (signum == 1) {
+            /*
+             * The following code draws on the algorithm presented in
+             * "Properly Rounded Variable Precision Square Root," Hull and
+             * Abrham, ACM Transactions on Mathematical Software, Vol 11,
+             * No. 3, September 1985, Pages 229-237.
+             *
+             * The BigDecimal computational model differs from the one
+             * presented in the paper in several ways: first BigDecimal
+             * numbers aren't necessarily normalized, second many more
+             * rounding modes are supported, including UNNECESSARY, and
+             * exact results can be requested.
+             *
+             * The main steps of the algorithm below are as follows,
+             * first argument reduce the value to the numerical range
+             * [1, 10) using the following relations:
+             *
+             * x = y * 10 ^ exp
+             * sqrt(x) = sqrt(y) * 10^(exp / 2) if exp is even
+             * sqrt(x) = sqrt(y/10) * 10 ^((exp+1)/2) is exp is odd
+             *
+             * Then use Newton's iteration on the reduced value to compute
+             * the numerical digits of the desired result.
+             *
+             * Finally, scale back to the desired exponent range and
+             * perform any adjustment to get the preferred scale in the
+             * representation.
+             */
+
+            // The code below favors relative simplicity over checking
+            // for special cases that could run faster.
+
+            int preferredScale = this.scale()/2;
+            BigDecimal zeroWithFinalPreferredScale = valueOf(0L, preferredScale);
+
+            // First phase of numerical normalization, strip trailing
+            // zeros and check for even powers of 10.
+            BigDecimal stripped = this.stripTrailingZeros();
+            int strippedScale = stripped.scale();
+
+            // Numerically sqrt(10^2N) = 10^N
+            if (stripped.isPowerOfTen() &&
+                strippedScale % 2 == 0) {
+                BigDecimal result = valueOf(1L, strippedScale/2);
+                if (result.scale() != preferredScale) {
+                    // Adjust to requested precision and preferred
+                    // scale as appropriate.
+                    result = result.add(zeroWithFinalPreferredScale, mc);
+                }
+                return result;
+            }
+
+            // After stripTrailingZeros, the representation is normalized as
+            //
+            // unscaledValue * 10^(-scale)
+            //
+            // where unscaledValue is an integer with the mimimum
+            // precision for the cohort of the numerical value. To
+            // allow binary floating-point hardware to be used to get
+            // approximately a 15 digit approximation to the square
+            // root, it is helpful to instead normalize this so that
+            // the significand portion is to right of the decimal
+            // point by roughly (scale() - precision() +1).
+
+            // Now the precision / scale adjustment
+            int scaleAdjust = 0;
+            int scale = stripped.scale() - stripped.precision() + 1;
+            if (scale % 2 == 0) {
+                scaleAdjust = scale;
+            } else {
+                scaleAdjust = scale - 1;
+            }
+
+            BigDecimal working = stripped.scaleByPowerOfTen(scaleAdjust);
+
+            assert  // Verify 0.1 <= working < 10
+                ONE_TENTH.compareTo(working) <= 0 && working.compareTo(TEN) < 0;
+
+            // Use good ole' Math.sqrt to get the initial guess for
+            // the Newton iteration, good to at least 15 decimal
+            // digits. This approach does incur the cost of a
+            //
+            // BigDecimal -> double -> BigDecimal
+            //
+            // conversion cycle, but it avoids the need for several
+            // Newton iterations in BigDecimal arithmetic to get the
+            // working answer to 15 digits of precision. If many fewer
+            // than 15 digits were needed, it might be faster to do
+            // the loop entirely in BigDecimal arithmetic.
+            //
+            // (A double value might have as much many as 17 decimal
+            // digits of precision; it depends on the relative density
+            // of binary and decimal numbers at different regions of
+            // the number line.)
+            //
+            // (It would be possible to check for certain special
+            // cases to avoid doing any Newton iterations. For
+            // example, if the BigDecimal -> double conversion was
+            // known to be exact and the rounding mode had a
+            // low-enough precision, the post-Newton rounding logic
+            // could be applied directly.)
+
+            BigDecimal guess = new BigDecimal(Math.sqrt(working.doubleValue()));
+            int guessPrecision = 15;
+            int originalPrecision = mc.getPrecision();
+            int targetPrecision;
+
+            // If an exact value is requested, it must only need about
+            // half of the input digits to represent since multiplying
+            // an N digit number by itself yield a 2N-1 digit or 2N
+            // digit result.
+            if (originalPrecision == 0) {
+                targetPrecision = stripped.precision()/2 + 1;
+            } else {
+                targetPrecision = originalPrecision;
+            }
+
+            // When setting the precision to use inside the Newton
+            // iteration loop, take care to avoid the case where the
+            // precision of the input exceeds the requested precision
+            // and rounding the input value too soon.
+            BigDecimal approx = guess;
+            int workingPrecision = working.precision();
+            do {
+                int tmpPrecision = Math.max(Math.max(guessPrecision, targetPrecision + 2),
+                                           workingPrecision);
+                MathContext mcTmp = new MathContext(tmpPrecision, RoundingMode.HALF_EVEN);
+                // approx = 0.5 * (approx + fraction / approx)
+                approx = ONE_HALF.multiply(approx.add(working.divide(approx, mcTmp), mcTmp));
+                guessPrecision *= 2;
+            } while (guessPrecision < targetPrecision + 2);
+
+            BigDecimal result;
+            RoundingMode targetRm = mc.getRoundingMode();
+            if (targetRm == RoundingMode.UNNECESSARY || originalPrecision == 0) {
+                RoundingMode tmpRm =
+                    (targetRm == RoundingMode.UNNECESSARY) ? RoundingMode.DOWN : targetRm;
+                MathContext mcTmp = new MathContext(targetPrecision, tmpRm);
+                result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mcTmp);
+
+                // If result*result != this numerically, the square
+                // root isn't exact
+                if (this.subtract(result.multiply(result)).compareTo(ZERO) != 0) {
+                    throw new ArithmeticException("Computed square root not exact.");
+                }
+            } else {
+                result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mc);
+            }
+
+            if (result.scale() != preferredScale) {
+                // The preferred scale of an add is
+                // max(addend.scale(), augend.scale()). Therefore, if
+                // the scale of the result is first minimized using
+                // stripTrailingZeros(), adding a zero of the
+                // preferred scale rounding the correct precision will
+                // perform the proper scale vs precision tradeoffs.
+                result = result.stripTrailingZeros().
+                    add(zeroWithFinalPreferredScale,
+                        new MathContext(originalPrecision, RoundingMode.UNNECESSARY));
+            }
+            assert squareRootResultAssertions(result, mc);
+            return result;
+        } else {
+            switch (signum) {
+            case -1:
+                throw new ArithmeticException("Attempted square root " +
+                                              "of negative BigDecimal");
+            case 0:
+                return valueOf(0L, scale()/2);
+
+            default:
+                throw new AssertionError("Bad value from signum");
+            }
+        }
+    }
+
+    private boolean isPowerOfTen() {
+        return BigInteger.ONE.equals(this.unscaledValue());
+    }
+
+    /**
+     * For nonzero values, check numerical correctness properties of
+     * the computed result for the chosen rounding mode.
+     *
+     * For the directed roundings, for DOWN and FLOOR, result^2 must
+     * be {@code <=} the input and (result+ulp)^2 must be {@code >} the
+     * input. Conversely, for UP and CEIL, result^2 must be {@code >=} the
+     * input and (result-ulp)^2 must be {@code <} the input.
+     */
+    private boolean squareRootResultAssertions(BigDecimal result, MathContext mc) {
+        if (result.signum() == 0) {
+            return squareRootZeroResultAssertions(result, mc);
+        } else {
+            RoundingMode rm = mc.getRoundingMode();
+            BigDecimal ulp = result.ulp();
+            BigDecimal neighborUp   = result.add(ulp);
+            // Make neighbor down accurate even for powers of ten
+            if (this.isPowerOfTen()) {
+                ulp = ulp.divide(TEN);
+            }
+            BigDecimal neighborDown = result.subtract(ulp);
+
+            // Both the starting value and result should be nonzero and positive.
+            if (result.signum() != 1 ||
+                this.signum() != 1) {
+                return false;
+            }
+
+            switch (rm) {
+            case DOWN:
+            case FLOOR:
+                return
+                    result.multiply(result).compareTo(this)         <= 0 &&
+                    neighborUp.multiply(neighborUp).compareTo(this) > 0;
+
+            case UP:
+            case CEILING:
+                return
+                    result.multiply(result).compareTo(this)             >= 0 &&
+                    neighborDown.multiply(neighborDown).compareTo(this) < 0;
+
+            case HALF_DOWN:
+            case HALF_EVEN:
+            case HALF_UP:
+                BigDecimal err = result.multiply(result).subtract(this).abs();
+                BigDecimal errUp = neighborUp.multiply(neighborUp).subtract(this);
+                BigDecimal errDown =  this.subtract(neighborDown.multiply(neighborDown));
+                // All error values should be positive so don't need to
+                // compare absolute values.
+
+                int err_comp_errUp = err.compareTo(errUp);
+                int err_comp_errDown = err.compareTo(errDown);
+
+                return
+                    errUp.signum()   == 1 &&
+                    errDown.signum() == 1 &&
+
+                    err_comp_errUp   <= 0 &&
+                    err_comp_errDown <= 0 &&
+
+                    ((err_comp_errUp   == 0 ) ? err_comp_errDown < 0 : true) &&
+                    ((err_comp_errDown == 0 ) ? err_comp_errUp   < 0 : true);
+                // && could check for digit conditions for ties too
+
+            default: // Definition of UNNECESSARY already verified.
+                return true;
+            }
+        }
+    }
+
+    private boolean squareRootZeroResultAssertions(BigDecimal result, MathContext mc) {
+        return this.compareTo(ZERO) == 0;
+    }
+
+    /**
      * Returns a {@code BigDecimal} whose value is
-     * <tt>(this<sup>n</sup>)</tt>, The power is computed exactly, to
+     * <code>(this<sup>n</sup>)</code>, The power is computed exactly, to
      * unlimited precision.
      *
      * <p>The parameter {@code n} must be in the range 0 through
@@ -2004,7 +2317,7 @@
      * range of this method.
      *
      * @param  n power to raise this {@code BigDecimal} to.
-     * @return <tt>this<sup>n</sup></tt>
+     * @return <code>this<sup>n</sup></code>
      * @throws ArithmeticException if {@code n} is out of range.
      * @since  1.5
      */
@@ -2020,7 +2333,7 @@
 
     /**
      * Returns a {@code BigDecimal} whose value is
-     * <tt>(this<sup>n</sup>)</tt>.  The current implementation uses
+     * <code>(this<sup>n</sup>)</code>.  The current implementation uses
      * the core algorithm defined in ANSI standard X3.274-1996 with
      * rounding according to the context settings.  In general, the
      * returned numerical value is within two ulps of the exact
@@ -2061,7 +2374,7 @@
      *
      * @param  n power to raise this {@code BigDecimal} to.
      * @param  mc the context to use.
-     * @return <tt>this<sup>n</sup></tt> using the ANSI standard X3.274-1996
+     * @return <code>this<sup>n</sup></code> using the ANSI standard X3.274-1996
      *         algorithm
      * @throws ArithmeticException if the result is inexact but the
      *         rounding mode is {@code UNNECESSARY}, or {@code n} is out
@@ -2249,8 +2562,8 @@
 
     /**
      * Returns a {@code BigInteger} whose value is the <i>unscaled
-     * value</i> of this {@code BigDecimal}.  (Computes <tt>(this *
-     * 10<sup>this.scale()</sup>)</tt>.)
+     * value</i> of this {@code BigDecimal}.  (Computes <code>(this *
+     * 10<sup>this.scale()</sup>)</code>.)
      *
      * @return the unscaled value of this {@code BigDecimal}.
      * @since  1.2
@@ -2265,15 +2578,21 @@
      * Rounding mode to round away from zero.  Always increments the
      * digit prior to a nonzero discarded fraction.  Note that this rounding
      * mode never decreases the magnitude of the calculated value.
+     *
+     * @deprecated Use {@link RoundingMode#UP} instead.
      */
-    public final static int ROUND_UP =           0;
+    @Deprecated(since="9")
+    public static final int ROUND_UP =           0;
 
     /**
      * Rounding mode to round towards zero.  Never increments the digit
      * prior to a discarded fraction (i.e., truncates).  Note that this
      * rounding mode never increases the magnitude of the calculated value.
+     *
+     * @deprecated Use {@link RoundingMode#DOWN} instead.
      */
-    public final static int ROUND_DOWN =         1;
+    @Deprecated(since="9")
+    public static final int ROUND_DOWN =         1;
 
     /**
      * Rounding mode to round towards positive infinity.  If the
@@ -2281,8 +2600,11 @@
      * {@code ROUND_UP}; if negative, behaves as for
      * {@code ROUND_DOWN}.  Note that this rounding mode never
      * decreases the calculated value.
+     *
+     * @deprecated Use {@link RoundingMode#CEILING} instead.
      */
-    public final static int ROUND_CEILING =      2;
+    @Deprecated(since="9")
+    public static final int ROUND_CEILING =      2;
 
     /**
      * Rounding mode to round towards negative infinity.  If the
@@ -2290,8 +2612,11 @@
      * {@code ROUND_DOWN}; if negative, behave as for
      * {@code ROUND_UP}.  Note that this rounding mode never
      * increases the calculated value.
+     *
+     * @deprecated Use {@link RoundingMode#FLOOR} instead.
      */
-    public final static int ROUND_FLOOR =        3;
+    @Deprecated(since="9")
+    public static final int ROUND_FLOOR =        3;
 
     /**
      * Rounding mode to round towards {@literal "nearest neighbor"}
@@ -2300,8 +2625,11 @@
      * &ge; 0.5; otherwise, behaves as for {@code ROUND_DOWN}.  Note
      * that this is the rounding mode that most of us were taught in
      * grade school.
+     *
+     * @deprecated Use {@link RoundingMode#HALF_UP} instead.
      */
-    public final static int ROUND_HALF_UP =      4;
+    @Deprecated(since="9")
+    public static final int ROUND_HALF_UP =      4;
 
     /**
      * Rounding mode to round towards {@literal "nearest neighbor"}
@@ -2309,8 +2637,11 @@
      * down.  Behaves as for {@code ROUND_UP} if the discarded
      * fraction is {@literal >} 0.5; otherwise, behaves as for
      * {@code ROUND_DOWN}.
+     *
+     * @deprecated Use {@link RoundingMode#HALF_DOWN} instead.
      */
-    public final static int ROUND_HALF_DOWN =    5;
+    @Deprecated(since="9")
+    public static final int ROUND_HALF_DOWN =    5;
 
     /**
      * Rounding mode to round towards the {@literal "nearest neighbor"}
@@ -2321,16 +2652,22 @@
      * {@code ROUND_HALF_DOWN} if it's even.  Note that this is the
      * rounding mode that minimizes cumulative error when applied
      * repeatedly over a sequence of calculations.
+     *
+     * @deprecated Use {@link RoundingMode#HALF_EVEN} instead.
      */
-    public final static int ROUND_HALF_EVEN =    6;
+    @Deprecated(since="9")
+    public static final int ROUND_HALF_EVEN =    6;
 
     /**
      * Rounding mode to assert that the requested operation has an exact
      * result, hence no rounding is necessary.  If this rounding mode is
      * specified on an operation that yields an inexact result, an
      * {@code ArithmeticException} is thrown.
+     *
+     * @deprecated Use {@link RoundingMode#UNNECESSARY} instead.
      */
-    public final static int ROUND_UNNECESSARY =  7;
+    @Deprecated(since="9")
+    public static final int ROUND_UNNECESSARY =  7;
 
 
     // Scaling/Rounding Operations
@@ -2366,10 +2703,10 @@
      * in this case, the specified rounding mode is applied to the
      * division.
      *
-     * <p>Note that since BigDecimal objects are immutable, calls of
-     * this method do <i>not</i> result in the original object being
+     * @apiNote Since BigDecimal objects are immutable, calls of
+     * this method do <em>not</em> result in the original object being
      * modified, contrary to the usual convention of having methods
-     * named <tt>set<i>X</i></tt> mutate field <i>{@code X}</i>.
+     * named <code>set<i>X</i></code> mutate field <i>{@code X}</i>.
      * Instead, {@code setScale} returns an object with the proper
      * scale; the returned object may or may not be newly allocated.
      *
@@ -2399,14 +2736,14 @@
      * in this case, the specified rounding mode is applied to the
      * division.
      *
-     * <p>Note that since BigDecimal objects are immutable, calls of
-     * this method do <i>not</i> result in the original object being
+     * @apiNote Since BigDecimal objects are immutable, calls of
+     * this method do <em>not</em> result in the original object being
      * modified, contrary to the usual convention of having methods
-     * named <tt>set<i>X</i></tt> mutate field <i>{@code X}</i>.
+     * named <code>set<i>X</i></code> mutate field <i>{@code X}</i>.
      * Instead, {@code setScale} returns an object with the proper
      * scale; the returned object may or may not be newly allocated.
      *
-     * <p>The new {@link #setScale(int, RoundingMode)} method should
+     * @deprecated The method {@link #setScale(int, RoundingMode)} should
      * be used in preference to this legacy method.
      *
      * @param  newScale scale of the {@code BigDecimal} value to be returned.
@@ -2429,6 +2766,7 @@
      * @see    #ROUND_HALF_EVEN
      * @see    #ROUND_UNNECESSARY
      */
+    @Deprecated(since="9")
     public BigDecimal setScale(int newScale, int roundingMode) {
         if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
             throw new IllegalArgumentException("Invalid rounding mode");
@@ -2493,10 +2831,10 @@
      * versions of {@code setScale}, but saves the caller the trouble
      * of specifying a rounding mode in cases where it is irrelevant.
      *
-     * <p>Note that since {@code BigDecimal} objects are immutable,
-     * calls of this method do <i>not</i> result in the original
+     * @apiNote Since {@code BigDecimal} objects are immutable,
+     * calls of this method do <em>not</em> result in the original
      * object being modified, contrary to the usual convention of
-     * having methods named <tt>set<i>X</i></tt> mutate field
+     * having methods named <code>set<i>X</i></code> mutate field
      * <i>{@code X}</i>.  Instead, {@code setScale} returns an
      * object with the proper scale; the returned object may or may
      * not be newly allocated.
@@ -2523,8 +2861,8 @@
      * {@code n} is non-negative, the call merely adds {@code n} to
      * the scale.  If {@code n} is negative, the call is equivalent
      * to {@code movePointRight(-n)}.  The {@code BigDecimal}
-     * returned by this call has value <tt>(this &times;
-     * 10<sup>-n</sup>)</tt> and scale {@code max(this.scale()+n,
+     * returned by this call has value <code>(this &times;
+     * 10<sup>-n</sup>)</code> and scale {@code max(this.scale()+n,
      * 0)}.
      *
      * @param  n number of places to move the decimal point to the left.
@@ -2545,8 +2883,8 @@
      * If {@code n} is non-negative, the call merely subtracts
      * {@code n} from the scale.  If {@code n} is negative, the call
      * is equivalent to {@code movePointLeft(-n)}.  The
-     * {@code BigDecimal} returned by this call has value <tt>(this
-     * &times; 10<sup>n</sup>)</tt> and scale {@code max(this.scale()-n,
+     * {@code BigDecimal} returned by this call has value <code>(this
+     * &times; 10<sup>n</sup>)</code> and scale {@code max(this.scale()-n,
      * 0)}.
      *
      * @param  n number of places to move the decimal point to the right.
@@ -2623,6 +2961,7 @@
      * @return -1, 0, or 1 as this {@code BigDecimal} is numerically
      *          less than, equal to, or greater than {@code val}.
      */
+    @Override
     public int compareTo(BigDecimal val) {
         // Quick path for equal scale and non-inflated case.
         if (scale == val.scale) {
@@ -2662,14 +3001,13 @@
                 return -1;
             if (xae > yae)
                 return 1;
-            BigInteger rb = null;
             if (sdiff < 0) {
                 // The cases sdiff <= Integer.MIN_VALUE intentionally fall through.
                 if ( sdiff > Integer.MIN_VALUE &&
                       (xs == INFLATED ||
                       (xs = longMultiplyPowerTen(xs, (int)-sdiff)) == INFLATED) &&
                      ys == INFLATED) {
-                    rb = bigMultiplyPowerTen((int)-sdiff);
+                    BigInteger rb = bigMultiplyPowerTen((int)-sdiff);
                     return rb.compareMagnitude(val.intVal);
                 }
             } else { // sdiff > 0
@@ -2678,7 +3016,7 @@
                       (ys == INFLATED ||
                       (ys = longMultiplyPowerTen(ys, (int)sdiff)) == INFLATED) &&
                      xs == INFLATED) {
-                    rb = val.bigMultiplyPowerTen((int)sdiff);
+                    BigInteger rb = val.bigMultiplyPowerTen((int)sdiff);
                     return this.intVal.compareMagnitude(rb);
                 }
             }
@@ -2762,7 +3100,7 @@
     /**
      * Returns the hash code for this {@code BigDecimal}.  Note that
      * two {@code BigDecimal} objects that are numerically equal but
-     * differ in scale (like 2.0 and 2.00) will generally <i>not</i>
+     * differ in scale (like 2.0 and 2.00) will generally <em>not</em>
      * have the same hash code.
      *
      * @return hash code for this {@code BigDecimal}.
@@ -2823,12 +3161,12 @@
      * adjusted exponent converted to a character form.  The latter is
      * in base ten, using the characters {@code '0'} through
      * {@code '9'} with no leading zeros, and is always prefixed by a
-     * sign character {@code '-'} (<tt>'&#92;u002D'</tt>) if the
+     * sign character {@code '-'} (<code>'&#92;u002D'</code>) if the
      * adjusted exponent is negative, {@code '+'}
-     * (<tt>'&#92;u002B'</tt>) otherwise).
+     * (<code>'&#92;u002B'</code>) otherwise).
      *
      * <p>Finally, the entire string is prefixed by a minus sign
-     * character {@code '-'} (<tt>'&#92;u002D'</tt>) if the unscaled
+     * character {@code '-'} (<code>'&#92;u002D'</code>) if the unscaled
      * value is less than zero.  No sign character is prefixed if the
      * unscaled value is zero or positive.
      *
@@ -2883,8 +3221,9 @@
     @Override
     public String toString() {
         String sc = stringCache;
-        if (sc == null)
+        if (sc == null) {
             stringCache = sc = layoutChars(true);
+        }
         return sc;
     }
 
@@ -2927,7 +3266,7 @@
      * in the result.
      *
      * The entire string is prefixed by a minus sign character '-'
-     * (<tt>'&#92;u002D'</tt>) if the unscaled value is less than
+     * (<code>'&#92;u002D'</code>) if the unscaled value is less than
      * zero. No sign character is prefixed if the unscaled value is
      * zero or positive.
      *
@@ -2961,18 +3300,19 @@
             if(signum()==0) {
                 return "0";
             }
-            int tailingZeros = checkScaleNonZero((-(long)scale));
+            int trailingZeros = checkScaleNonZero((-(long)scale));
             StringBuilder buf;
             if(intCompact!=INFLATED) {
-                buf = new StringBuilder(20+tailingZeros);
+                buf = new StringBuilder(20+trailingZeros);
                 buf.append(intCompact);
             } else {
                 String str = intVal.toString();
-                buf = new StringBuilder(str.length()+tailingZeros);
+                buf = new StringBuilder(str.length()+trailingZeros);
                 buf.append(str);
             }
-            for (int i = 0; i < tailingZeros; i++)
+            for (int i = 0; i < trailingZeros; i++) {
                 buf.append('0');
+            }
             return buf.toString();
         }
         String str ;
@@ -2999,8 +3339,9 @@
         } else { /* We must insert zeros between point and intVal */
             buf = new StringBuilder(3-insertionPoint + intString.length());
             buf.append(signum<0 ? "-0." : "0.");
-            for (int i=0; i<-insertionPoint; i++)
+            for (int i=0; i<-insertionPoint; i++) {
                 buf.append('0');
+            }
             buf.append(intString);
         }
         return buf.toString();
@@ -3010,7 +3351,7 @@
      * Converts this {@code BigDecimal} to a {@code BigInteger}.
      * This conversion is analogous to the
      * <i>narrowing primitive conversion</i> from {@code double} to
-     * {@code long} as defined in section 5.1.3 of
+     * {@code long} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * any fractional part of this
      * {@code BigDecimal} will be discarded.  Note that this
@@ -3022,6 +3363,7 @@
      * {@link #toBigIntegerExact()} method.
      *
      * @return this {@code BigDecimal} converted to a {@code BigInteger}.
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
     public BigInteger toBigInteger() {
         // force to an integer, quietly
@@ -3047,7 +3389,7 @@
      * Converts this {@code BigDecimal} to a {@code long}.
      * This conversion is analogous to the
      * <i>narrowing primitive conversion</i> from {@code double} to
-     * {@code short} as defined in section 5.1.3 of
+     * {@code short} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * any fractional part of this
      * {@code BigDecimal} will be discarded, and if the resulting
@@ -3058,34 +3400,13 @@
      * as return a result with the opposite sign.
      *
      * @return this {@code BigDecimal} converted to a {@code long}.
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
+    @Override
     public long longValue(){
-        if (intCompact != INFLATED && scale == 0) {
-            return intCompact;
-        } else {
-            // Fastpath zero and small values
-            if (this.signum() == 0 || fractionOnly() ||
-                // Fastpath very large-scale values that will result
-                // in a truncated value of zero. If the scale is -64
-                // or less, there are at least 64 powers of 10 in the
-                // value of the numerical result. Since 10 = 2*5, in
-                // that case there would also be 64 powers of 2 in the
-                // result, meaning all 64 bits of a long will be zero.
-                scale <= -64) {
-                return 0;
-            } else {
-                return toBigInteger().longValue();
-            }
-        }
-    }
-
-    /**
-     * Return true if a nonzero BigDecimal has an absolute value less
-     * than one; i.e. only has fraction digits.
-     */
-    private boolean fractionOnly() {
-        assert this.signum() != 0;
-        return (this.precision() - this.scale) <= 0;
+        return (intCompact != INFLATED && scale == 0) ?
+            intCompact:
+            toBigInteger().longValue();
     }
 
     /**
@@ -3103,20 +3424,15 @@
     public long longValueExact() {
         if (intCompact != INFLATED && scale == 0)
             return intCompact;
-
-        // Fastpath zero
-        if (this.signum() == 0)
-            return 0;
-
-        // Fastpath numbers less than 1.0 (the latter can be very slow
-        // to round if very small)
-        if (fractionOnly())
-            throw new ArithmeticException("Rounding necessary");
-
         // If more than 19 digits in integer part it cannot possibly fit
         if ((precision() - scale) > 19) // [OK for negative scale too]
             throw new java.lang.ArithmeticException("Overflow");
-
+        // Fastpath zero and < 1.0 numbers (the latter can be very slow
+        // to round if very small)
+        if (this.signum() == 0)
+            return 0;
+        if ((this.precision() - this.scale) <= 0)
+            throw new ArithmeticException("Rounding necessary");
         // round to an integer, with Exception if decimal part non-0
         BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
         if (num.precision() >= 19) // need to check carefully
@@ -3143,7 +3459,7 @@
      * Converts this {@code BigDecimal} to an {@code int}.
      * This conversion is analogous to the
      * <i>narrowing primitive conversion</i> from {@code double} to
-     * {@code short} as defined in section 5.1.3 of
+     * {@code short} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * any fractional part of this
      * {@code BigDecimal} will be discarded, and if the resulting
@@ -3154,11 +3470,13 @@
      * value as well as return a result with the opposite sign.
      *
      * @return this {@code BigDecimal} converted to an {@code int}.
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
+    @Override
     public int intValue() {
         return  (intCompact != INFLATED && scale == 0) ?
             (int)intCompact :
-            (int)longValue();
+            toBigInteger().intValue();
     }
 
     /**
@@ -3225,7 +3543,7 @@
      * Converts this {@code BigDecimal} to a {@code float}.
      * This conversion is similar to the
      * <i>narrowing primitive conversion</i> from {@code double} to
-     * {@code float} as defined in section 5.1.3 of
+     * {@code float} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * if this {@code BigDecimal} has too great a
      * magnitude to represent as a {@code float}, it will be
@@ -3236,7 +3554,9 @@
      * value.
      *
      * @return this {@code BigDecimal} converted to a {@code float}.
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
+    @Override
     public float floatValue(){
         if(intCompact != INFLATED) {
             if (scale == 0) {
@@ -3252,10 +3572,10 @@
                     // Don't have too guard against
                     // Math.abs(MIN_VALUE) because of outer check
                     // against INFLATED.
-                    if (scale > 0 && scale < float10pow.length) {
-                        return (float)intCompact / float10pow[scale];
-                    } else if (scale < 0 && scale > -float10pow.length) {
-                        return (float)intCompact * float10pow[-scale];
+                    if (scale > 0 && scale < FLOAT_10_POW.length) {
+                        return (float)intCompact / FLOAT_10_POW[scale];
+                    } else if (scale < 0 && scale > -FLOAT_10_POW.length) {
+                        return (float)intCompact * FLOAT_10_POW[-scale];
                     }
                 }
             }
@@ -3268,7 +3588,7 @@
      * Converts this {@code BigDecimal} to a {@code double}.
      * This conversion is similar to the
      * <i>narrowing primitive conversion</i> from {@code double} to
-     * {@code float} as defined in section 5.1.3 of
+     * {@code float} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * if this {@code BigDecimal} has too great a
      * magnitude represent as a {@code double}, it will be
@@ -3279,7 +3599,9 @@
      * value.
      *
      * @return this {@code BigDecimal} converted to a {@code double}.
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
+    @Override
     public double doubleValue(){
         if(intCompact != INFLATED) {
             if (scale == 0) {
@@ -3295,10 +3617,10 @@
                     // Don't have too guard against
                     // Math.abs(MIN_VALUE) because of outer check
                     // against INFLATED.
-                    if (scale > 0 && scale < double10pow.length) {
-                        return (double)intCompact / double10pow[scale];
-                    } else if (scale < 0 && scale > -double10pow.length) {
-                        return (double)intCompact * double10pow[-scale];
+                    if (scale > 0 && scale < DOUBLE_10_POW.length) {
+                        return (double)intCompact / DOUBLE_10_POW[scale];
+                    } else if (scale < 0 && scale > -DOUBLE_10_POW.length) {
+                        return (double)intCompact * DOUBLE_10_POW[-scale];
                     }
                 }
             }
@@ -3311,7 +3633,7 @@
      * Powers of 10 which can be represented exactly in {@code
      * double}.
      */
-    private static final double double10pow[] = {
+    private static final double DOUBLE_10_POW[] = {
         1.0e0,  1.0e1,  1.0e2,  1.0e3,  1.0e4,  1.0e5,
         1.0e6,  1.0e7,  1.0e8,  1.0e9,  1.0e10, 1.0e11,
         1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17,
@@ -3322,7 +3644,7 @@
      * Powers of 10 which can be represented exactly in {@code
      * float}.
      */
-    private static final float float10pow[] = {
+    private static final float FLOAT_10_POW[] = {
         1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
         1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
     };
@@ -3417,7 +3739,7 @@
             return charPos;
         }
 
-        final static char[] DIGIT_TENS = {
+        static final char[] DIGIT_TENS = {
             '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
             '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
             '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
@@ -3430,7 +3752,7 @@
             '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
         };
 
-        final static char[] DIGIT_ONES = {
+        static final char[] DIGIT_ONES = {
             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
@@ -3535,8 +3857,9 @@
                 } else if (sig >= coeffLen) {   // significand all in integer
                     buf.append(coeff, offset, coeffLen);
                     // may need some zeros, too
-                    for (int i = sig - coeffLen; i > 0; i--)
+                    for (int i = sig - coeffLen; i > 0; i--) {
                         buf.append('0');
+                    }
                 } else {                     // xx.xxE form
                     buf.append(coeff, offset, sig);
                     buf.append('.');
@@ -3590,11 +3913,13 @@
             // to prevent multiple threads from expanding the same array.
             if (curLen <= n) {
                 int newLen = curLen << 1;
-                while (newLen <= n)
+                while (newLen <= n) {
                     newLen <<= 1;
+                }
                 pows = Arrays.copyOf(pows, newLen);
-                for (int i = curLen; i < newLen; i++)
+                for (int i = curLen; i < newLen; i++) {
                     pows[i] = pows[i - 1].multiply(BigInteger.TEN);
+                }
                 // Based on the following facts:
                 // 1. pows is a private local variable;
                 // 2. the following store is a volatile store.
@@ -3734,9 +4059,7 @@
      *         {@code BigDecimal}s to be aligned.
      */
     private static void matchScale(BigDecimal[] val) {
-        if (val[0].scale == val[1].scale) {
-            return;
-        } else if (val[0].scale < val[1].scale) {
+        if (val[0].scale < val[1].scale) {
             val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
         } else if (val[1].scale < val[0].scale) {
             val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
@@ -4240,16 +4563,16 @@
      * do rounding based on the passed in roundingMode.
      */
     private static BigInteger divideAndRound(BigInteger bdividend, long ldivisor, int roundingMode) {
-        boolean isRemainderZero; // record remainder is zero or not
-        int qsign; // quotient sign
-        long r = 0; // store quotient & remainder in long
-        MutableBigInteger mq = null; // store quotient
         // Descend into mutables for faster remainder checks
         MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
-        mq = new MutableBigInteger();
-        r = mdividend.divide(ldivisor, mq);
-        isRemainderZero = (r == 0);
-        qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+        // store quotient
+        MutableBigInteger mq = new MutableBigInteger();
+        // store quotient & remainder in long
+        long r = mdividend.divide(ldivisor, mq);
+        // record remainder is zero or not
+        boolean isRemainderZero = (r == 0);
+        // quotient sign
+        int qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
         if (!isRemainderZero) {
             if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
                 mq.add(MutableBigInteger.ONE);
@@ -4269,16 +4592,16 @@
      */
     private static BigDecimal divideAndRound(BigInteger bdividend,
                                              long ldivisor, int scale, int roundingMode, int preferredScale) {
-        boolean isRemainderZero; // record remainder is zero or not
-        int qsign; // quotient sign
-        long r = 0; // store quotient & remainder in long
-        MutableBigInteger mq = null; // store quotient
         // Descend into mutables for faster remainder checks
         MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
-        mq = new MutableBigInteger();
-        r = mdividend.divide(ldivisor, mq);
-        isRemainderZero = (r == 0);
-        qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+        // store quotient
+        MutableBigInteger mq = new MutableBigInteger();
+        // store quotient & remainder in long
+        long r = mdividend.divide(ldivisor, mq);
+        // record remainder is zero or not
+        boolean isRemainderZero = (r == 0);
+        // quotient sign
+        int qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
         if (!isRemainderZero) {
             if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
                 mq.add(MutableBigInteger.ONE);
diff --git a/ojluni/src/main/java/java/math/BigInteger.java b/ojluni/src/main/java/java/math/BigInteger.java
index 3a23c8f..9801b67e 100644
--- a/ojluni/src/main/java/java/math/BigInteger.java
+++ b/ojluni/src/main/java/java/math/BigInteger.java
@@ -34,12 +34,14 @@
 import java.io.ObjectOutputStream;
 import java.io.ObjectStreamField;
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.ThreadLocalRandom;
-import libcore.math.NativeBN;
+
 import jdk.internal.math.DoubleConsts;
 import jdk.internal.math.FloatConsts;
 
+import libcore.math.NativeBN;
 /**
  * Immutable arbitrary-precision integers.  All operations behave as if
  * BigIntegers were represented in two's-complement notation (like Java's
@@ -50,19 +52,17 @@
  * and a few other miscellaneous operations.
  *
  * <p>Semantics of arithmetic operations exactly mimic those of Java's integer
- * arithmetic operators, as defined in <i>The Java Language Specification</i>.
+ * arithmetic operators, as defined in <i>The Java&trade; Language Specification</i>.
  * For example, division by zero throws an {@code ArithmeticException}, and
  * division of a negative by a positive yields a negative (or zero) remainder.
- * All of the details in the Spec concerning overflow are ignored, as
- * BigIntegers are made as large as necessary to accommodate the results of an
- * operation.
  *
  * <p>Semantics of shift operations extend those of Java's shift operators
  * to allow for negative shift distances.  A right-shift with a negative
  * shift distance results in a left shift, and vice-versa.  The unsigned
- * right shift operator ({@code >>>}) is omitted, as this operation makes
- * little sense in combination with the "infinite word size" abstraction
- * provided by this class.
+ * right shift operator ({@code >>>}) is omitted since this operation
+ * only makes sense for a fixed sized word and not for a
+ * representation conceptually having an infinite number of leading
+ * virtual sign bits.
  *
  * <p>Semantics of bitwise logical operations exactly mimic those of Java's
  * bitwise integer operators.  The binary operators ({@code and},
@@ -82,8 +82,8 @@
  * extended so that it contains the designated bit.  None of the single-bit
  * operations can produce a BigInteger with a different sign from the
  * BigInteger being operated on, as they affect only a single bit, and the
- * "infinite word size" abstraction provided by this class ensures that there
- * are infinitely many "virtual sign bits" preceding each BigInteger.
+ * arbitrarily large abstraction provided by this class ensures that conceptually
+ * there are infinitely many "virtual sign bits" preceding each BigInteger.
  *
  * <p>For the sake of brevity and clarity, pseudo-code is used throughout the
  * descriptions of BigInteger methods.  The pseudo-code expression
@@ -103,33 +103,36 @@
  * +2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive)
  * and may support values outside of that range.
  *
+ * An {@code ArithmeticException} is thrown when a BigInteger
+ * constructor or method would generate a value outside of the
+ * supported range.
+ *
  * The range of probable prime values is limited and may be less than
  * the full supported positive range of {@code BigInteger}.
  * The range must be at least 1 to 2<sup>500000000</sup>.
  *
  * @implNote
- * BigInteger constructors and operations throw {@code ArithmeticException} when
- * the result is out of the supported range of
+ * In the reference implementation, BigInteger constructors and
+ * operations throw {@code ArithmeticException} when the result is out
+ * of the supported range of
  * -2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive) to
  * +2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive).
  *
  * @see     BigDecimal
+ * @jls     4.2.2 Integer Operations
  * @author  Josh Bloch
  * @author  Michael McCloskey
  * @author  Alan Eliasen
  * @author  Timothy Buktu
- * @since JDK1.1
+ * @since 1.1
  */
 
 public class BigInteger extends Number implements Comparable<BigInteger> {
-
     /**
      * The signum of this BigInteger: -1 for negative, 0 for zero, or
-     * 1 for positive.  Note that the BigInteger zero <i>must</i> have
+     * 1 for positive.  Note that the BigInteger zero <em>must</em> have
      * a signum of 0.  This is necessary to ensures that there is exactly one
      * representation for each BigInteger value.
-     *
-     * @serial
      */
     final int signum;
 
@@ -144,60 +147,48 @@
      */
     final int[] mag;
 
-    // These "redundant fields" are initialized with recognizable nonsense
-    // values, and cached the first time they are needed (or never, if they
-    // aren't needed).
-
-     /**
-     * One plus the bitCount of this BigInteger. Zeros means uninitialized.
-     *
-     * @serial
-     * @see #bitCount
-     * @deprecated Deprecated since logical value is offset from stored
-     * value and correction factor is applied in accessor method.
-     */
-    @Deprecated
-    private int bitCount;
+    // The following fields are stable variables. A stable variable's value
+    // changes at most once from the default zero value to a non-zero stable
+    // value. A stable value is calculated lazily on demand.
 
     /**
-     * One plus the bitLength of this BigInteger. Zeros means uninitialized.
+     * One plus the bitCount of this BigInteger. This is a stable variable.
+     *
+     * @see #bitCount
+     */
+    private int bitCountPlusOne;
+
+    /**
+     * One plus the bitLength of this BigInteger. This is a stable variable.
      * (either value is acceptable).
      *
-     * @serial
      * @see #bitLength()
-     * @deprecated Deprecated since logical value is offset from stored
-     * value and correction factor is applied in accessor method.
      */
-    @Deprecated
-    private int bitLength;
+    private int bitLengthPlusOne;
 
     /**
-     * Two plus the lowest set bit of this BigInteger, as returned by
-     * getLowestSetBit().
+     * Two plus the lowest set bit of this BigInteger. This is a stable variable.
      *
-     * @serial
      * @see #getLowestSetBit
-     * @deprecated Deprecated since logical value is offset from stored
-     * value and correction factor is applied in accessor method.
      */
-    @Deprecated
-    private int lowestSetBit;
+    private int lowestSetBitPlusTwo;
 
     /**
      * Two plus the index of the lowest-order int in the magnitude of this
-     * BigInteger that contains a nonzero int, or -2 (either value is acceptable).
-     * The least significant int has int-number 0, the next int in order of
+     * BigInteger that contains a nonzero int. This is a stable variable. The
+     * least significant int has int-number 0, the next int in order of
      * increasing significance has int-number 1, and so forth.
-     * @deprecated Deprecated since logical value is offset from stored
-     * value and correction factor is applied in accessor method.
+     *
+     * <p>Note: never used for a BigInteger with a magnitude of zero.
+     *
+     * @see #firstNonzeroIntNum()
      */
-    @Deprecated
-    private int firstNonzeroIntNum;
+    private int firstNonzeroIntNumPlusTwo;
 
     /**
      * This mask is used to obtain the value of an int as if it were unsigned.
      */
-    final static long LONG_MASK = 0xffffffffL;
+    static final long LONG_MASK = 0xffffffffL;
 
     /**
      * This constant limits {@code mag.length} of BigIntegers to the supported
@@ -290,24 +281,41 @@
     // Constructors
 
     /**
-     * Translates a byte array containing the two's-complement binary
-     * representation of a BigInteger into a BigInteger.  The input array is
+     * Translates a byte sub-array containing the two's-complement binary
+     * representation of a BigInteger into a BigInteger.  The sub-array is
+     * specified via an offset into the array and a length.  The sub-array is
      * assumed to be in <i>big-endian</i> byte-order: the most significant
-     * byte is in the zeroth element.
+     * byte is the element at index {@code off}.  The {@code val} array is
+     * assumed to be unchanged for the duration of the constructor call.
      *
-     * @param  val big-endian two's-complement binary representation of
-     *         BigInteger.
+     * An {@code IndexOutOfBoundsException} is thrown if the length of the array
+     * {@code val} is non-zero and either {@code off} is negative, {@code len}
+     * is negative, or {@code off+len} is greater than the length of
+     * {@code val}.
+     *
+     * @param  val byte array containing a sub-array which is the big-endian
+     *         two's-complement binary representation of a BigInteger.
+     * @param  off the start offset of the binary representation.
+     * @param  len the number of bytes to use.
      * @throws NumberFormatException {@code val} is zero bytes long.
+     * @throws IndexOutOfBoundsException if the provided array offset and
+     *         length would cause an index into the byte array to be
+     *         negative or greater than or equal to the array length.
+     * @since 9
      */
-    public BigInteger(byte[] val) {
-        if (val.length == 0)
+    public BigInteger(byte[] val, int off, int len) {
+        if (val.length == 0) {
             throw new NumberFormatException("Zero length BigInteger");
+        } else if ((off < 0) || (off >= val.length) || (len < 0) ||
+                   (len > val.length - off)) { // 0 <= off < val.length
+            throw new IndexOutOfBoundsException();
+        }
 
-        if (val[0] < 0) {
-            mag = makePositive(val);
+        if (val[off] < 0) {
+            mag = makePositive(val, off, len);
             signum = -1;
         } else {
-            mag = stripLeadingZeroBytes(val);
+            mag = stripLeadingZeroBytes(val, off, len);
             signum = (mag.length == 0 ? 0 : 1);
         }
         if (mag.length >= MAX_MAG_LENGTH) {
@@ -316,10 +324,27 @@
     }
 
     /**
+     * Translates a byte array containing the two's-complement binary
+     * representation of a BigInteger into a BigInteger.  The input array is
+     * assumed to be in <i>big-endian</i> byte-order: the most significant
+     * byte is in the zeroth element.  The {@code val} array is assumed to be
+     * unchanged for the duration of the constructor call.
+     *
+     * @param  val big-endian two's-complement binary representation of a
+     *         BigInteger.
+     * @throws NumberFormatException {@code val} is zero bytes long.
+     */
+    public BigInteger(byte[] val) {
+        this(val, 0, val.length);
+    }
+
+    /**
      * This private constructor translates an int array containing the
      * two's-complement binary representation of a BigInteger into a
      * BigInteger. The input array is assumed to be in <i>big-endian</i>
-     * int-order: the most significant int is in the zeroth element.
+     * int-order: the most significant int is in the zeroth element.  The
+     * {@code val} array is assumed to be unchanged for the duration of
+     * the constructor call.
      */
     private BigInteger(int[] val) {
         if (val.length == 0)
@@ -340,24 +365,44 @@
     /**
      * Translates the sign-magnitude representation of a BigInteger into a
      * BigInteger.  The sign is represented as an integer signum value: -1 for
-     * negative, 0 for zero, or 1 for positive.  The magnitude is a byte array
-     * in <i>big-endian</i> byte-order: the most significant byte is in the
-     * zeroth element.  A zero-length magnitude array is permissible, and will
-     * result in a BigInteger value of 0, whether signum is -1, 0 or 1.
+     * negative, 0 for zero, or 1 for positive.  The magnitude is a sub-array of
+     * a byte array in <i>big-endian</i> byte-order: the most significant byte
+     * is the element at index {@code off}.  A zero value of the length
+     * {@code len} is permissible, and will result in a BigInteger value of 0,
+     * whether signum is -1, 0 or 1.  The {@code magnitude} array is assumed to
+     * be unchanged for the duration of the constructor call.
+     *
+     * An {@code IndexOutOfBoundsException} is thrown if the length of the array
+     * {@code magnitude} is non-zero and either {@code off} is negative,
+     * {@code len} is negative, or {@code off+len} is greater than the length of
+     * {@code magnitude}.
      *
      * @param  signum signum of the number (-1 for negative, 0 for zero, 1
      *         for positive).
      * @param  magnitude big-endian binary representation of the magnitude of
      *         the number.
+     * @param  off the start offset of the binary representation.
+     * @param  len the number of bytes to use.
      * @throws NumberFormatException {@code signum} is not one of the three
      *         legal values (-1, 0, and 1), or {@code signum} is 0 and
      *         {@code magnitude} contains one or more non-zero bytes.
+     * @throws IndexOutOfBoundsException if the provided array offset and
+     *         length would cause an index into the byte array to be
+     *         negative or greater than or equal to the array length.
+     * @since 9
      */
-    public BigInteger(int signum, byte[] magnitude) {
-        this.mag = stripLeadingZeroBytes(magnitude);
-
-        if (signum < -1 || signum > 1)
+    public BigInteger(int signum, byte[] magnitude, int off, int len) {
+        if (signum < -1 || signum > 1) {
             throw(new NumberFormatException("Invalid signum value"));
+        } else if ((off < 0) || (len < 0) ||
+            (len > 0 &&
+                ((off >= magnitude.length) ||
+                 (len > magnitude.length - off)))) { // 0 <= off < magnitude.length
+            throw new IndexOutOfBoundsException();
+        }
+
+        // stripLeadingZeroBytes() returns a zero length array if len == 0
+        this.mag = stripLeadingZeroBytes(magnitude, off, len);
 
         if (this.mag.length == 0) {
             this.signum = 0;
@@ -372,10 +417,33 @@
     }
 
     /**
+     * Translates the sign-magnitude representation of a BigInteger into a
+     * BigInteger.  The sign is represented as an integer signum value: -1 for
+     * negative, 0 for zero, or 1 for positive.  The magnitude is a byte array
+     * in <i>big-endian</i> byte-order: the most significant byte is the
+     * zeroth element.  A zero-length magnitude array is permissible, and will
+     * result in a BigInteger value of 0, whether signum is -1, 0 or 1.  The
+     * {@code magnitude} array is assumed to be unchanged for the duration of
+     * the constructor call.
+     *
+     * @param  signum signum of the number (-1 for negative, 0 for zero, 1
+     *         for positive).
+     * @param  magnitude big-endian binary representation of the magnitude of
+     *         the number.
+     * @throws NumberFormatException {@code signum} is not one of the three
+     *         legal values (-1, 0, and 1), or {@code signum} is 0 and
+     *         {@code magnitude} contains one or more non-zero bytes.
+     */
+    public BigInteger(int signum, byte[] magnitude) {
+         this(signum, magnitude, 0, magnitude.length);
+    }
+
+    /**
      * A constructor for internal use that translates the sign-magnitude
      * representation of a BigInteger into a BigInteger. It checks the
      * arguments and copies the magnitude so this constructor would be
-     * safe for external use.
+     * safe for external use.  The {@code magnitude} array is assumed to be
+     * unchanged for the duration of the constructor call.
      */
     private BigInteger(int signum, int[] magnitude) {
         this.mag = stripLeadingZeroInts(magnitude);
@@ -492,7 +560,9 @@
 
     /*
      * Constructs a new BigInteger using a char array with radix=10.
-     * Sign is precalculated outside and not allowed in the val.
+     * Sign is precalculated outside and not allowed in the val. The {@code val}
+     * array is assumed to be unchanged for the duration of the constructor
+     * call.
      */
     BigInteger(char[] val, int sign, int len) {
         int cursor = 0, numDigits;
@@ -644,7 +714,7 @@
      * Constructs a randomly generated positive BigInteger that is probably
      * prime, with the specified bitLength.
      *
-     * <p>It is recommended that the {@link #probablePrime probablePrime}
+     * @apiNote It is recommended that the {@link #probablePrime probablePrime}
      * method be used in preference to this constructor unless there
      * is a compelling need to specify a certainty.
      *
@@ -1060,11 +1130,12 @@
 
     /**
      * This private constructor is for internal use and assumes that its
-     * arguments are correct.
+     * arguments are correct.  The {@code magnitude} array is assumed to be
+     * unchanged for the duration of the constructor call.
      */
     private BigInteger(byte[] magnitude, int signum) {
         this.signum = (magnitude.length == 0 ? 0 : signum);
-        this.mag = stripLeadingZeroBytes(magnitude);
+        this.mag = stripLeadingZeroBytes(magnitude, 0, magnitude.length);
         if (mag.length >= MAX_MAG_LENGTH) {
             checkRange();
         }
@@ -1090,9 +1161,11 @@
 
     /**
      * Returns a BigInteger whose value is equal to that of the
-     * specified {@code long}.  This "static factory method" is
-     * provided in preference to a ({@code long}) constructor
-     * because it allows for reuse of frequently used BigIntegers.
+     * specified {@code long}.
+     *
+     * @apiNote This static factory method is provided in preference
+     * to a ({@code long}) constructor because it allows for reuse of
+     * frequently used BigIntegers.
      *
      * @param  val value of the BigInteger to return.
      * @return a BigInteger with the specified value.
@@ -1145,7 +1218,7 @@
     /**
      * Initialize static constant array when class is loaded.
      */
-    private final static int MAX_CONSTANT = 16;
+    private static final int MAX_CONSTANT = 16;
     private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
     private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];
 
@@ -1163,14 +1236,6 @@
     private static final double LOG_TWO = Math.log(2.0);
 
     static {
-        assert 0 < KARATSUBA_THRESHOLD
-            && KARATSUBA_THRESHOLD < TOOM_COOK_THRESHOLD
-            && TOOM_COOK_THRESHOLD < Integer.MAX_VALUE
-            && 0 < KARATSUBA_SQUARE_THRESHOLD
-            && KARATSUBA_SQUARE_THRESHOLD < TOOM_COOK_SQUARE_THRESHOLD
-            && TOOM_COOK_SQUARE_THRESHOLD < Integer.MAX_VALUE :
-            "Algorithm thresholds are inconsistent";
-
         for (int i = 1; i <= MAX_CONSTANT; i++) {
             int[] magnitude = new int[1];
             magnitude[0] = i;
@@ -1207,9 +1272,11 @@
     public static final BigInteger ONE = valueOf(1);
 
     /**
-     * The BigInteger constant two.  (Not exported.)
+     * The BigInteger constant two.
+     *
+     * @since   9
      */
-    private static final BigInteger TWO = valueOf(2);
+    public static final BigInteger TWO = valueOf(2);
 
     /**
      * The BigInteger constant -1.  (Not exported.)
@@ -1492,18 +1559,6 @@
      * @return {@code this * val}
      */
     public BigInteger multiply(BigInteger val) {
-        return multiply(val, false);
-    }
-
-    /**
-     * Returns a BigInteger whose value is {@code (this * val)}.  If
-     * the invocation is recursive certain overflow checks are skipped.
-     *
-     * @param  val value to be multiplied by this BigInteger.
-     * @param  isRecursion whether this is a recursive invocation
-     * @return {@code this * val}
-     */
-    private BigInteger multiply(BigInteger val, boolean isRecursion) {
         if (val.signum == 0 || signum == 0)
             return ZERO;
 
@@ -1511,17 +1566,17 @@
 
         // BEGIN Android-changed: Fall back to the boringssl implementation for
         // large arguments.
-        int ylen = val.mag.length;
-
         final int BORINGSSL_MUL_THRESHOLD = 50;
 
+        if (val == this && xlen > MULTIPLY_SQUARE_THRESHOLD
+                && xlen < BORINGSSL_MUL_THRESHOLD) {
+            return square();
+        }
+
+        int ylen = val.mag.length;
+
         int resultSign = signum == val.signum ? 1 : -1;
         if ((xlen < BORINGSSL_MUL_THRESHOLD) || (ylen < BORINGSSL_MUL_THRESHOLD)) {
-            if (val == this && xlen > MULTIPLY_SQUARE_THRESHOLD) {
-                // Helps less than boringssl fallback; prefer that.
-                return square();
-            }
-
             if (val.mag.length == 1) {
                 return multiplyByInt(mag,val.mag[0], resultSign);
             }
@@ -1610,6 +1665,8 @@
                 return multiplyToomCook3(this, val);
             }
             */
+        // END Android-changed: Fall back to the boringssl implementation for
+        // large arguments.
         }
     }
 
@@ -1682,11 +1739,19 @@
      * the result into z. There will be no leading zeros in the resultant array.
      */
     private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
+        multiplyToLenCheck(x, xlen);
+        multiplyToLenCheck(y, ylen);
+        return implMultiplyToLen(x, xlen, y, ylen, z);
+    }
+
+    // Android-removed: @HotSpotIntrinsicCandidate
+    // @HotSpotIntrinsicCandidate
+    private static int[] implMultiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
         int xstart = xlen - 1;
         int ystart = ylen - 1;
 
         if (z == null || z.length < (xlen+ ylen))
-             z = new int[xlen+ylen];
+            z = new int[xlen+ylen];
 
         long carry = 0;
         for (int j=ystart, k=ystart+1+xstart; j >= 0; j--, k--) {
@@ -1711,6 +1776,18 @@
         return z;
     }
 
+    private static void multiplyToLenCheck(int[] array, int length) {
+        if (length <= 0) {
+            return;  // not an error because multiplyToLen won't execute if len <= 0
+        }
+
+        Objects.requireNonNull(array);
+
+        if (length > array.length) {
+            throw new ArrayIndexOutOfBoundsException(length - 1);
+        }
+    }
+
     /**
      * Multiplies two BigIntegers using the Karatsuba multiplication
      * algorithm.  This is a recursive divide-and-conquer algorithm which is
@@ -1808,16 +1885,16 @@
 
         BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1, db1;
 
-        v0 = a0.multiply(b0, true);
+        v0 = a0.multiply(b0);
         da1 = a2.add(a0);
         db1 = b2.add(b0);
-        vm1 = da1.subtract(a1).multiply(db1.subtract(b1), true);
+        vm1 = da1.subtract(a1).multiply(db1.subtract(b1));
         da1 = da1.add(a1);
         db1 = db1.add(b1);
-        v1 = da1.multiply(db1, true);
+        v1 = da1.multiply(db1);
         v2 = da1.add(a2).shiftLeft(1).subtract(a0).multiply(
-             db1.add(b2).shiftLeft(1).subtract(b0), true);
-        vinf = a2.multiply(b2, true);
+             db1.add(b2).shiftLeft(1).subtract(b0));
+        vinf = a2.multiply(b2);
 
         // The algorithm requires two divisions by 2 and one by 3.
         // All divisions are known to be exact, that is, they do not produce
@@ -1983,17 +2060,6 @@
      * @return {@code this<sup>2</sup>}
      */
     private BigInteger square() {
-        return square(false);
-    }
-
-    /**
-     * Returns a BigInteger whose value is {@code (this<sup>2</sup>)}. If
-     * the invocation is recursive certain overflow checks are skipped.
-     *
-     * @param isRecursion whether this is a recursive invocation
-     * @return {@code this<sup>2</sup>}
-     */
-    private BigInteger square(boolean isRecursion) {
         if (signum == 0) {
             return ZERO;
         }
@@ -2006,15 +2072,6 @@
             if (len < TOOM_COOK_SQUARE_THRESHOLD) {
                 return squareKaratsuba();
             } else {
-                //
-                // For a discussion of overflow detection see multiply()
-                //
-                if (!isRecursion) {
-                    if (bitLength(mag, mag.length) > 16L*MAX_MAG_LENGTH) {
-                        reportOverflow();
-                    }
-                }
-
                 return squareToomCook3();
             }
         }
@@ -2061,6 +2118,8 @@
      /**
       * Java Runtime may use intrinsic for this method.
       */
+     // Android-removed: @HotSpotIntrinsicCandidate
+     // @HotSpotIntrinsicCandidate
      private static final int[] implSquareToLen(int[] x, int len, int[] z, int zlen) {
         /*
          * The algorithm used here is adapted from Colin Plumb's C library.
@@ -2165,13 +2224,13 @@
         a0 = getToomSlice(k, r, 2, len);
         BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1;
 
-        v0 = a0.square(true);
+        v0 = a0.square();
         da1 = a2.add(a0);
-        vm1 = da1.subtract(a1).square(true);
+        vm1 = da1.subtract(a1).square();
         da1 = da1.add(a1);
-        v1 = da1.square(true);
-        vinf = a2.square(true);
-        v2 = da1.add(a2).shiftLeft(1).subtract(a0).square(true);
+        v1 = da1.square();
+        vinf = a2.square();
+        v2 = da1.add(a2).shiftLeft(1).subtract(a0).square();
 
         // The algorithm requires two divisions by 2 and one by 3.
         // All divisions are known to be exact, that is, they do not produce
@@ -2196,7 +2255,7 @@
     // Division
 
 
-    // BEGIN Android-modified: Fall back to boringssl for large problems.
+    // BEGIN Android-changed: Fall back to boringssl for large problems.
     private static final int BORINGSSL_DIV_THRESHOLD = 40;
     private static final int BORINGSSL_DIV_OFFSET = 20;
 
@@ -2214,11 +2273,11 @@
                 mag.length - val.mag.length < BORINGSSL_DIV_OFFSET) {
             return divideKnuth(val);
         } else {
-            return divideAndRemainder(val)[0];
             // return divideBurnikelZiegler(val);
+            return divideAndRemainder(val)[0];
         }
     }
-    // END Android-modified: Fall back to boringssl for large problems.
+    // END Android-changed: Fall back to boringssl for large problems.
 
 
     /**
@@ -2250,15 +2309,19 @@
      * @throws ArithmeticException if {@code val} is zero.
      */
     public BigInteger[] divideAndRemainder(BigInteger val) {
-        // BEGIN Android-modified: Fall back to boringssl for large problems.
-
-        // if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD ||
-        //        mag.length - val.mag < BURNIKEL_ZIEGLER_OFFSET) {
+        // BEGIN Android-changed: Fall back to boringssl for large problems.
+        /*
+        if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD ||
+               mag.length - val.mag < BURNIKEL_ZIEGLER_OFFSET) {
+         */
         if (val.mag.length < BORINGSSL_DIV_THRESHOLD ||
                 mag.length < BORINGSSL_DIV_OFFSET ||
                 mag.length - val.mag.length < BORINGSSL_DIV_OFFSET) {
             return divideAndRemainderKnuth(val);
         } else {
+            /*
+            return divideAndRemainderBurnikelZiegler(val);
+            */
             int quotSign = signum == val.signum ? 1 : -1;  // 0 divided doesn't get here.
             long xBN = 0, yBN = 0, quotBN = 0, remBN = 0;
             try {
@@ -2278,9 +2341,8 @@
                 NativeBN.BN_free(quotBN);
                 NativeBN.BN_free(remBN);
             }
-            // return divideAndRemainderBurnikelZiegler(val);
         }
-        // END Android-modified: Fall back to boringssl for large problems.
+        // END Android-changed: Fall back to boringssl for large problems.
     }
 
     /** Long division */
@@ -2304,17 +2366,19 @@
      * @throws ArithmeticException if {@code val} is zero.
      */
     public BigInteger remainder(BigInteger val) {
-        // BEGIN Android-modified: Fall back to boringssl for large problems.
-        // if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD ||
-        //        mag.length - val.mag.length < BURNIKEL_ZIEGLER_OFFSET) {
+        // BEGIN Android-changed: Fall back to boringssl for large problems.
+        /*
+        if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD ||
+               mag.length - val.mag.length < BURNIKEL_ZIEGLER_OFFSET) {
+         */
         if (val.mag.length < BORINGSSL_DIV_THRESHOLD ||
                 mag.length - val.mag.length < BORINGSSL_DIV_THRESHOLD) {
             return remainderKnuth(val);
         } else {
-            return divideAndRemainder(val)[1];
             // return remainderBurnikelZiegler(val);
+            return divideAndRemainder(val)[1];
         }
-        // END Android-modified: Fall back to boringssl for large problems.
+        // END Android-changed: Fall back to boringssl for large problems.
     }
 
     /** Long division */
@@ -2359,11 +2423,11 @@
     }
 
     /**
-     * Returns a BigInteger whose value is <tt>(this<sup>exponent</sup>)</tt>.
+     * Returns a BigInteger whose value is <code>(this<sup>exponent</sup>)</code>.
      * Note that {@code exponent} is an integer rather than a BigInteger.
      *
      * @param  exponent exponent to which this BigInteger is to be raised.
-     * @return <tt>this<sup>exponent</sup></tt>
+     * @return <code>this<sup>exponent</sup></code>
      * @throws ArithmeticException {@code exponent} is negative.  (This would
      *         cause the operation to yield a non-integer value.)
      */
@@ -2382,11 +2446,10 @@
         // The remaining part can then be exponentiated faster.  The
         // powers of two will be multiplied back at the end.
         int powersOfTwo = partToSquare.getLowestSetBit();
-        long bitsToShiftLong = (long)powersOfTwo * exponent;
-        if (bitsToShiftLong > Integer.MAX_VALUE) {
+        long bitsToShift = (long)powersOfTwo * exponent;
+        if (bitsToShift > Integer.MAX_VALUE) {
             reportOverflow();
         }
-        int bitsToShift = (int)bitsToShiftLong;
 
         int remainingBits;
 
@@ -2396,9 +2459,9 @@
             remainingBits = partToSquare.bitLength();
             if (remainingBits == 1) {  // Nothing left but +/- 1?
                 if (signum < 0 && (exponent&1) == 1) {
-                    return NEGATIVE_ONE.shiftLeft(bitsToShift);
+                    return NEGATIVE_ONE.shiftLeft(powersOfTwo*exponent);
                 } else {
-                    return ONE.shiftLeft(bitsToShift);
+                    return ONE.shiftLeft(powersOfTwo*exponent);
                 }
             }
         } else {
@@ -2443,16 +2506,13 @@
                 if (bitsToShift + scaleFactor <= 62) { // Fits in long?
                     return valueOf((result << bitsToShift) * newSign);
                 } else {
-                    return valueOf(result*newSign).shiftLeft(bitsToShift);
+                    return valueOf(result*newSign).shiftLeft((int) bitsToShift);
                 }
-            } else {
+            }
+            else {
                 return valueOf(result*newSign);
             }
         } else {
-            if ((long)bitLength() * exponent / Integer.SIZE > MAX_MAG_LENGTH) {
-                reportOverflow();
-            }
-
             // Large number algorithm.  This is basically identical to
             // the algorithm above, but calls multiply() and square()
             // which may use more efficient algorithms for large numbers.
@@ -2472,7 +2532,7 @@
             // Multiply back the (exponentiated) powers of two (quickly,
             // by shifting left)
             if (powersOfTwo > 0) {
-                answer = answer.shiftLeft(bitsToShift);
+                answer = answer.shiftLeft(powersOfTwo*exponent);
             }
 
             if (signum < 0 && (exponent&1) == 1) {
@@ -2484,6 +2544,53 @@
     }
 
     /**
+     * Returns the integer square root of this BigInteger.  The integer square
+     * root of the corresponding mathematical integer {@code n} is the largest
+     * mathematical integer {@code s} such that {@code s*s <= n}.  It is equal
+     * to the value of {@code floor(sqrt(n))}, where {@code sqrt(n)} denotes the
+     * real square root of {@code n} treated as a real.  Note that the integer
+     * square root will be less than the real square root if the latter is not
+     * representable as an integral value.
+     *
+     * @return the integer square root of {@code this}
+     * @throws ArithmeticException if {@code this} is negative.  (The square
+     *         root of a negative integer {@code val} is
+     *         {@code (i * sqrt(-val))} where <i>i</i> is the
+     *         <i>imaginary unit</i> and is equal to
+     *         {@code sqrt(-1)}.)
+     * @since  9
+     */
+    public BigInteger sqrt() {
+        if (this.signum < 0) {
+            throw new ArithmeticException("Negative BigInteger");
+        }
+
+        return new MutableBigInteger(this.mag).sqrt().toBigInteger();
+    }
+
+    /**
+     * Returns an array of two BigIntegers containing the integer square root
+     * {@code s} of {@code this} and its remainder {@code this - s*s},
+     * respectively.
+     *
+     * @return an array of two BigIntegers with the integer square root at
+     *         offset 0 and the remainder at offset 1
+     * @throws ArithmeticException if {@code this} is negative.  (The square
+     *         root of a negative integer {@code val} is
+     *         {@code (i * sqrt(-val))} where <i>i</i> is the
+     *         <i>imaginary unit</i> and is equal to
+     *         {@code sqrt(-1)}.)
+     * @see #sqrt()
+     * @since  9
+     */
+    public BigInteger[] sqrtAndRemainder() {
+        BigInteger s = sqrt();
+        BigInteger r = this.subtract(s.square());
+        assert r.compareTo(BigInteger.ZERO) >= 0;
+        return new BigInteger[] {s, r};
+    }
+
+    /**
      * Returns a BigInteger whose value is the greatest common divisor of
      * {@code abs(this)} and {@code abs(val)}.  Returns 0 if
      * {@code this == 0 && val == 0}.
@@ -2655,12 +2762,12 @@
 
     /**
      * Returns a BigInteger whose value is
-     * <tt>(this<sup>exponent</sup> mod m)</tt>.  (Unlike {@code pow}, this
+     * <code>(this<sup>exponent</sup> mod m)</code>.  (Unlike {@code pow}, this
      * method permits negative exponents.)
      *
      * @param  exponent the exponent.
      * @param  m the modulus.
-     * @return <tt>this<sup>exponent</sup> mod m</tt>
+     * @return <code>this<sup>exponent</sup> mod m</code>
      * @throws ArithmeticException {@code m} &le; 0 or the exponent is
      *         negative and this BigInteger is not <i>relatively
      *         prime</i> to {@code m}.
@@ -2814,13 +2921,17 @@
          return z;
     }
 
-    // These methods are intended to be be replaced by virtual machine
+    // These methods are intended to be replaced by virtual machine
     // intrinsics.
+    // Android-removed: @HotSpotIntrinsicCandidate
+    // @HotSpotIntrinsicCandidate
     private static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len,
                                          long inv, int[] product) {
         product = multiplyToLen(a, len, b, len, product);
         return montReduce(product, n, len, (int)inv);
     }
+    // Android-removed: @HotSpotIntrinsicCandidate
+    // @HotSpotIntrinsicCandidate
     private static int[] implMontgomerySquare(int[] a, int[] n, int len,
                                        long inv, int[] product) {
         product = squareToLen(a, len, product);
@@ -3152,6 +3263,8 @@
     /**
      * Java Runtime may use intrinsic for this method.
      */
+    // Android-removed: @HotSpotIntrinsicCandidate
+    // @HotSpotIntrinsicCandidate
     private static int implMulAdd(int[] out, int[] in, int offset, int len, int k) {
         long kLong = k & LONG_MASK;
         long carry = 0;
@@ -3274,7 +3387,7 @@
      * Returns a BigInteger whose value is {@code (this << n)}.
      * The shift distance, {@code n}, may be negative, in which case
      * this method performs a right shift.
-     * (Computes <tt>floor(this * 2<sup>n</sup>)</tt>.)
+     * (Computes <code>floor(this * 2<sup>n</sup>)</code>.)
      *
      * @param  n shift distance, in bits.
      * @return {@code this << n}
@@ -3297,7 +3410,7 @@
     /**
      * Returns a magnitude array whose value is {@code (mag << n)}.
      * The shift distance, {@code n}, is considered unnsigned.
-     * (Computes <tt>this * 2<sup>n</sup></tt>.)
+     * (Computes <code>this * 2<sup>n</sup></code>.)
      *
      * @param mag magnitude, the most-significant int ({@code mag[0]}) must be non-zero.
      * @param  n unsigned shift distance, in bits.
@@ -3334,7 +3447,7 @@
      * Returns a BigInteger whose value is {@code (this >> n)}.  Sign
      * extension is performed.  The shift distance, {@code n}, may be
      * negative, in which case this method performs a left shift.
-     * (Computes <tt>floor(this / 2<sup>n</sup>)</tt>.)
+     * (Computes <code>floor(this / 2<sup>n</sup>)</code>.)
      *
      * @param  n shift distance, in bits.
      * @return {@code this >> n}
@@ -3357,7 +3470,7 @@
     /**
      * Returns a BigInteger whose value is {@code (this >> n)}. The shift
      * distance, {@code n}, is considered unsigned.
-     * (Computes <tt>floor(this * 2<sup>-n</sup>)</tt>.)
+     * (Computes <code>floor(this * 2<sup>-n</sup>)</code>.)
      *
      * @param  n unsigned shift distance, in bits.
      * @return {@code this >> n}
@@ -3602,7 +3715,7 @@
      * @return index of the rightmost one bit in this BigInteger.
      */
     public int getLowestSetBit() {
-        @SuppressWarnings("deprecation") int lsb = lowestSetBit - 2;
+        int lsb = lowestSetBitPlusTwo - 2;
         if (lsb == -2) {  // lowestSetBit not initialized yet
             lsb = 0;
             if (signum == 0) {
@@ -3614,7 +3727,7 @@
                     ;
                 lsb += (i << 5) + Integer.numberOfTrailingZeros(b);
             }
-            lowestSetBit = lsb + 2;
+            lowestSetBitPlusTwo = lsb + 2;
         }
         return lsb;
     }
@@ -3624,16 +3737,16 @@
 
     /**
      * Returns the number of bits in the minimal two's-complement
-     * representation of this BigInteger, <i>excluding</i> a sign bit.
+     * representation of this BigInteger, <em>excluding</em> a sign bit.
      * For positive BigIntegers, this is equivalent to the number of bits in
-     * the ordinary binary representation.  (Computes
-     * {@code (ceil(log2(this < 0 ? -this : this+1)))}.)
+     * the ordinary binary representation.  For zero this method returns
+     * {@code 0}.  (Computes {@code (ceil(log2(this < 0 ? -this : this+1)))}.)
      *
      * @return number of bits in the minimal two's-complement
-     *         representation of this BigInteger, <i>excluding</i> a sign bit.
+     *         representation of this BigInteger, <em>excluding</em> a sign bit.
      */
     public int bitLength() {
-        @SuppressWarnings("deprecation") int n = bitLength - 1;
+        int n = bitLengthPlusOne - 1;
         if (n == -1) { // bitLength not initialized yet
             int[] m = mag;
             int len = m.length;
@@ -3648,12 +3761,12 @@
                      for (int i=1; i< len && pow2; i++)
                          pow2 = (mag[i] == 0);
 
-                     n = (pow2 ? magBitLength - 1 : magBitLength);
+                     n = (pow2 ? magBitLength -1 : magBitLength);
                  } else {
                      n = magBitLength;
                  }
             }
-            bitLength = n + 1;
+            bitLengthPlusOne = n + 1;
         }
         return n;
     }
@@ -3667,7 +3780,7 @@
      *         of this BigInteger that differ from its sign bit.
      */
     public int bitCount() {
-        @SuppressWarnings("deprecation") int bc = bitCount - 1;
+        int bc = bitCountPlusOne - 1;
         if (bc == -1) {  // bitCount not initialized yet
             bc = 0;      // offset by one to initialize
             // Count the bits in the magnitude
@@ -3681,7 +3794,7 @@
                 magTrailingZeroCount += Integer.numberOfTrailingZeros(mag[j]);
                 bc += magTrailingZeroCount - 1;
             }
-            bitCount = bc + 1;
+            bitCountPlusOne = bc + 1;
         }
         return bc;
     }
@@ -3973,7 +4086,7 @@
      * Converts the specified BigInteger to a string and appends to
      * {@code sb}.  This implements the recursive Schoenhage algorithm
      * for base conversions.
-     * <p/>
+     * <p>
      * See Knuth, Donald,  _The Art of Computer Programming_, Vol. 2,
      * Answers to Exercises (4.4) Question 14.
      *
@@ -3984,16 +4097,16 @@
      */
     private static void toString(BigInteger u, StringBuilder sb, int radix,
                                  int digits) {
-        /* If we're smaller than a certain threshold, use the smallToString
-           method, padding with leading zeroes when necessary. */
+        // If we're smaller than a certain threshold, use the smallToString
+        // method, padding with leading zeroes when necessary.
         if (u.mag.length <= SCHOENHAGE_BASE_CONVERSION_THRESHOLD) {
             String s = u.smallToString(radix);
 
             // Pad with internal zeros if necessary.
             // Don't pad if we're at the beginning of the string.
             if ((s.length() < digits) && (sb.length() > 0)) {
-                for (int i=s.length(); i < digits; i++) { // May be a faster way to
-                    sb.append('0');                    // do this?
+                for (int i=s.length(); i < digits; i++) {
+                    sb.append('0');
                 }
             }
 
@@ -4022,7 +4135,7 @@
     /**
      * Returns the value radix^(2^exponent) from the cache.
      * If this value doesn't already exist in the cache, it is added.
-     * <p/>
+     * <p>
      * This could be changed to a more complicated caching method using
      * {@code Future}.
      */
@@ -4107,7 +4220,7 @@
      * Converts this BigInteger to an {@code int}.  This
      * conversion is analogous to a
      * <i>narrowing primitive conversion</i> from {@code long} to
-     * {@code int} as defined in section 5.1.3 of
+     * {@code int} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * if this BigInteger is too big to fit in an
      * {@code int}, only the low-order 32 bits are returned.
@@ -4117,6 +4230,7 @@
      *
      * @return this BigInteger converted to an {@code int}.
      * @see #intValueExact()
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
     public int intValue() {
         int result = 0;
@@ -4128,7 +4242,7 @@
      * Converts this BigInteger to a {@code long}.  This
      * conversion is analogous to a
      * <i>narrowing primitive conversion</i> from {@code long} to
-     * {@code int} as defined in section 5.1.3 of
+     * {@code int} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * if this BigInteger is too big to fit in a
      * {@code long}, only the low-order 64 bits are returned.
@@ -4138,6 +4252,7 @@
      *
      * @return this BigInteger converted to a {@code long}.
      * @see #longValueExact()
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
     public long longValue() {
         long result = 0;
@@ -4151,7 +4266,7 @@
      * Converts this BigInteger to a {@code float}.  This
      * conversion is similar to the
      * <i>narrowing primitive conversion</i> from {@code double} to
-     * {@code float} as defined in section 5.1.3 of
+     * {@code float} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * if this BigInteger has too great a magnitude
      * to represent as a {@code float}, it will be converted to
@@ -4161,6 +4276,7 @@
      * information about the precision of the BigInteger value.
      *
      * @return this BigInteger converted to a {@code float}.
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
     public float floatValue() {
         if (signum == 0) {
@@ -4235,7 +4351,7 @@
      * Converts this BigInteger to a {@code double}.  This
      * conversion is similar to the
      * <i>narrowing primitive conversion</i> from {@code double} to
-     * {@code float} as defined in section 5.1.3 of
+     * {@code float} as defined in
      * <cite>The Java&trade; Language Specification</cite>:
      * if this BigInteger has too great a magnitude
      * to represent as a {@code double}, it will be converted to
@@ -4245,6 +4361,7 @@
      * information about the precision of the BigInteger value.
      *
      * @return this BigInteger converted to a {@code double}.
+     * @jls 5.1.3 Narrowing Primitive Conversion
      */
     public double doubleValue() {
         if (signum == 0) {
@@ -4353,18 +4470,18 @@
     /**
      * Returns a copy of the input array stripped of any leading zero bytes.
      */
-    private static int[] stripLeadingZeroBytes(byte a[]) {
-        int byteLength = a.length;
+    private static int[] stripLeadingZeroBytes(byte a[], int off, int len) {
+        int indexBound = off + len;
         int keep;
 
         // Find first nonzero byte
-        for (keep = 0; keep < byteLength && a[keep] == 0; keep++)
+        for (keep = off; keep < indexBound && a[keep] == 0; keep++)
             ;
 
         // Allocate new array and copy relevant part of input array
-        int intLength = ((byteLength - keep) + 3) >>> 2;
+        int intLength = ((indexBound - keep) + 3) >>> 2;
         int[] result = new int[intLength];
-        int b = byteLength - 1;
+        int b = indexBound - 1;
         for (int i = intLength-1; i >= 0; i--) {
             result[i] = a[b--] & 0xff;
             int bytesRemaining = b - keep + 1;
@@ -4379,27 +4496,27 @@
      * Takes an array a representing a negative 2's-complement number and
      * returns the minimal (no leading zero bytes) unsigned whose value is -a.
      */
-    private static int[] makePositive(byte a[]) {
+    private static int[] makePositive(byte a[], int off, int len) {
         int keep, k;
-        int byteLength = a.length;
+        int indexBound = off + len;
 
         // Find first non-sign (0xff) byte of input
-        for (keep=0; keep < byteLength && a[keep] == -1; keep++)
+        for (keep=off; keep < indexBound && a[keep] == -1; keep++)
             ;
 
 
         /* Allocate output array.  If all non-sign bytes are 0x00, we must
          * allocate space for one extra output byte. */
-        for (k=keep; k < byteLength && a[k] == 0; k++)
+        for (k=keep; k < indexBound && a[k] == 0; k++)
             ;
 
-        int extraByte = (k == byteLength) ? 1 : 0;
-        int intLength = ((byteLength - keep + extraByte) + 3) >>> 2;
+        int extraByte = (k == indexBound) ? 1 : 0;
+        int intLength = ((indexBound - keep + extraByte) + 3) >>> 2;
         int result[] = new int[intLength];
 
         /* Copy one's complement of input into output, leaving extra
          * byte (if it exists) == 0x00 */
-        int b = byteLength - 1;
+        int b = indexBound - 1;
         for (int i = intLength-1; i >= 0; i--) {
             result[i] = a[b--] & 0xff;
             int numBytesToTransfer = Math.min(3, b-keep+1);
@@ -4547,22 +4664,23 @@
     }
 
     /**
-     * Returns the index of the int that contains the first nonzero int in the
-     * little-endian binary representation of the magnitude (int 0 is the
-     * least significant). If the magnitude is zero, return value is undefined.
-     */
+    * Returns the index of the int that contains the first nonzero int in the
+    * little-endian binary representation of the magnitude (int 0 is the
+    * least significant). If the magnitude is zero, return value is undefined.
+    *
+    * <p>Note: never used for a BigInteger with a magnitude of zero.
+    * @see #getInt.
+    */
     private int firstNonzeroIntNum() {
-        int fn = firstNonzeroIntNum - 2;
+        int fn = firstNonzeroIntNumPlusTwo - 2;
         if (fn == -2) { // firstNonzeroIntNum not initialized yet
-            fn = 0;
-
             // Search for the first nonzero int
             int i;
             int mlen = mag.length;
             for (i = mlen - 1; i >= 0 && mag[i] == 0; i--)
                 ;
             fn = mlen - i - 1;
-            firstNonzeroIntNum = fn + 2; // offset by two to initialize
+            firstNonzeroIntNumPlusTwo = fn + 2; // offset by two to initialize
         }
         return fn;
     }
@@ -4574,16 +4692,17 @@
      * Serializable fields for BigInteger.
      *
      * @serialField signum  int
-     *              signum of this BigInteger.
-     * @serialField magnitude int[]
-     *              magnitude array of this BigInteger.
+     *              signum of this BigInteger
+     * @serialField magnitude byte[]
+     *              magnitude array of this BigInteger
      * @serialField bitCount  int
-     *              number of bits in this BigInteger
+     *              appears in the serialized form for backward compatibility
      * @serialField bitLength int
-     *              the number of bits in the minimal two's-complement
-     *              representation of this BigInteger
+     *              appears in the serialized form for backward compatibility
+     * @serialField firstNonzeroByteNum int
+     *              appears in the serialized form for backward compatibility
      * @serialField lowestSetBit int
-     *              lowest set bit in the twos complement representation
+     *              appears in the serialized form for backward compatibility
      */
     private static final ObjectStreamField[] serialPersistentFields = {
         new ObjectStreamField("signum", Integer.TYPE),
@@ -4600,22 +4719,14 @@
      * for historical reasons, but it is converted to an array of ints
      * and the byte array is discarded.
      * Note:
-     * The current convention is to initialize the cache fields, bitCount,
-     * bitLength and lowestSetBit, to 0 rather than some other marker value.
-     * Therefore, no explicit action to set these fields needs to be taken in
-     * readObject because those fields already have a 0 value be default since
-     * defaultReadObject is not being used.
+     * The current convention is to initialize the cache fields, bitCountPlusOne,
+     * bitLengthPlusOne and lowestSetBitPlusTwo, to 0 rather than some other
+     * marker value. Therefore, no explicit action to set these fields needs to
+     * be taken in readObject because those fields already have a 0 value by
+     * default since defaultReadObject is not being used.
      */
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
-        /*
-         * In order to maintain compatibility with previous serialized forms,
-         * the magnitude of a BigInteger is serialized as an array of bytes.
-         * The magnitude field is used as a temporary store for the byte array
-         * that is deserialized. The cached computation fields should be
-         * transient but are serialized for compatibility reasons.
-         */
-
         // prepare to read the alternate persistent fields
         ObjectInputStream.GetField fields = s.readFields();
 
@@ -4630,7 +4741,7 @@
                 message = "BigInteger: Signum not present in stream";
             throw new java.io.StreamCorruptedException(message);
         }
-        int[] mag = stripLeadingZeroBytes(magnitude);
+        int[] mag = stripLeadingZeroBytes(magnitude, 0, magnitude.length);
         if ((mag.length == 0) != (sign == 0)) {
             String message = "BigInteger: signum-magnitude mismatch";
             if (fields.defaulted("magnitude"))
@@ -4679,12 +4790,14 @@
     }
 
     /**
-     * Save the {@code BigInteger} instance to a stream.
-     * The magnitude of a BigInteger is serialized as a byte array for
-     * historical reasons.
-     *
-     * @serialData two necessary fields are written as well as obsolete
-     *             fields for compatibility with older versions.
+     * Save the {@code BigInteger} instance to a stream.  The magnitude of a
+     * {@code BigInteger} is serialized as a byte array for historical reasons.
+     * To maintain compatibility with older implementations, the integers
+     * -1, -1, -2, and -2 are written as the values of the obsolete fields
+     * {@code bitCount}, {@code bitLength}, {@code lowestSetBit}, and
+     * {@code firstNonzeroByteNum}, respectively.  These values are compatible
+     * with older implementations, but will be ignored by current
+     * implementations.
      */
     private void writeObject(ObjectOutputStream s) throws IOException {
         // set the values of the Serializable fields
@@ -4694,15 +4807,17 @@
         // The values written for cached fields are compatible with older
         // versions, but are ignored in readObject so don't otherwise matter.
         // BEGIN Android-changed: Don't include the following fields.
-        // fields.put("bitCount", -1);
-        // fields.put("bitLength", -1);
-        // fields.put("lowestSetBit", -2);
-        // fields.put("firstNonzeroByteNum", -2);
-        // END Android-changed
+        /*
+        fields.put("bitCount", -1);
+        fields.put("bitLength", -1);
+        fields.put("lowestSetBit", -2);
+        fields.put("firstNonzeroByteNum", -2);
+        */
+        // END Android-changed: Don't include the following fields.
 
         // save them
         s.writeFields();
-}
+    }
 
     /**
      * Returns the mag array as an array of bytes.
@@ -4755,7 +4870,7 @@
      *
      * @return this {@code BigInteger} converted to an {@code int}.
      * @throws ArithmeticException if the value of {@code this} will
-     * not exactly fit in a {@code int}.
+     * not exactly fit in an {@code int}.
      * @see BigInteger#intValue
      * @since  1.8
      */
diff --git a/ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java b/ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java
index 0de212d..d389df3 100644
--- a/ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java
+++ b/ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, 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
@@ -26,7 +26,14 @@
 package java.nio.channels.spi;
 
 import java.io.IOException;
-import java.nio.channels.*;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.IllegalSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
 
 
 /**
@@ -67,8 +74,8 @@
     // Lock for registration and configureBlocking operations
     private final Object regLock = new Object();
 
-    // Blocking mode, protected by regLock
-    boolean blocking = true;
+    // True when non-blocking, need regLock to change;
+    private volatile boolean nonBlocking;
 
     /**
      * Initializes a new instance of this class.
@@ -101,7 +108,7 @@
                 if (keys[i] == null)
                     break;
         } else if (keys == null) {
-            keys =  new SelectionKey[3];
+            keys = new SelectionKey[2];
         } else {
             // Grow key array
             int n = keys.length * 2;
@@ -116,14 +123,14 @@
     }
 
     private SelectionKey findKey(Selector sel) {
-        synchronized (keyLock) {
-            if (keys == null)
-                return null;
-            for (int i = 0; i < keys.length; i++)
-                if ((keys[i] != null) && (keys[i].selector() == sel))
-                    return keys[i];
+        assert Thread.holdsLock(keyLock);
+        if (keys == null)
             return null;
-        }
+        for (int i = 0; i < keys.length; i++)
+            if ((keys[i] != null) && (keys[i].selector() == sel))
+                return keys[i];
+        return null;
+
     }
 
     void removeKey(SelectionKey k) {                    // package-private
@@ -159,7 +166,9 @@
     }
 
     public final SelectionKey keyFor(Selector sel) {
-        return findKey(sel);
+        synchronized (keyLock) {
+            return findKey(sel);
+        }
     }
 
     /**
@@ -188,32 +197,31 @@
      *
      * @throws  IllegalArgumentException {@inheritDoc}
      */
-    public final SelectionKey register(Selector sel, int ops,
-                                       Object att)
+    public final SelectionKey register(Selector sel, int ops, Object att)
         throws ClosedChannelException
     {
+        if ((ops & ~validOps()) != 0)
+            throw new IllegalArgumentException();
+        if (!isOpen())
+            throw new ClosedChannelException();
         synchronized (regLock) {
-            if (!isOpen())
-                throw new ClosedChannelException();
-            if ((ops & ~validOps()) != 0)
-                throw new IllegalArgumentException();
-            if (blocking)
+            if (isBlocking())
                 throw new IllegalBlockingModeException();
-            SelectionKey k = findKey(sel);
-            if (k != null) {
-                k.interestOps(ops);
-                k.attach(att);
-            }
-            if (k == null) {
-                // New registration
-                synchronized (keyLock) {
-                    if (!isOpen())
-                        throw new ClosedChannelException();
+            synchronized (keyLock) {
+                // re-check if channel has been closed
+                if (!isOpen())
+                    throw new ClosedChannelException();
+                SelectionKey k = findKey(sel);
+                if (k != null) {
+                    k.attach(att);
+                    k.interestOps(ops);
+                } else {
+                    // New registration
                     k = ((AbstractSelector)sel).register(this, ops, att);
                     addKey(k);
                 }
+                return k;
             }
-            return k;
         }
     }
 
@@ -232,12 +240,20 @@
      */
     protected final void implCloseChannel() throws IOException {
         implCloseSelectableChannel();
+
+        // clone keys to avoid calling cancel when holding keyLock
+        SelectionKey[] copyOfKeys = null;
         synchronized (keyLock) {
-            int count = (keys == null) ? 0 : keys.length;
-            for (int i = 0; i < count; i++) {
-                SelectionKey k = keys[i];
-                if (k != null)
-                    k.cancel();
+            if (keys != null) {
+                copyOfKeys = keys.clone();
+            }
+        }
+
+        if (copyOfKeys != null) {
+            for (SelectionKey k : copyOfKeys) {
+                if (k != null) {
+                    k.cancel();   // invalidate and adds key to cancelledKey set
+                }
             }
         }
     }
@@ -264,9 +280,7 @@
     // -- Blocking --
 
     public final boolean isBlocking() {
-        synchronized (regLock) {
-            return blocking;
-        }
+        return !nonBlocking;
     }
 
     public final Object blockingLock() {
@@ -287,12 +301,13 @@
         synchronized (regLock) {
             if (!isOpen())
                 throw new ClosedChannelException();
-            if (blocking == block)
-                return this;
-            if (block && haveValidKeys())
-                throw new IllegalBlockingModeException();
-            implConfigureBlocking(block);
-            blocking = block;
+            boolean blocking = !nonBlocking;
+            if (block != blocking) {
+                if (block && haveValidKeys())
+                    throw new IllegalBlockingModeException();
+                implConfigureBlocking(block);
+                nonBlocking = !block;
+            }
         }
         return this;
     }
@@ -305,8 +320,8 @@
      * changing the blocking mode.  This method is only invoked if the new mode
      * is different from the current mode.  </p>
      *
-     * @param  block  If <tt>true</tt> then this channel will be placed in
-     *                blocking mode; if <tt>false</tt> then it will be placed
+     * @param  block  If {@code true} then this channel will be placed in
+     *                blocking mode; if {@code false} then it will be placed
      *                non-blocking mode
      *
      * @throws IOException
diff --git a/ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java b/ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java
index 09e3b61..9aab22f 100644
--- a/ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java
+++ b/ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -43,9 +43,9 @@
  * after, respectively, invoking an I/O operation that might block
  * indefinitely.  In order to ensure that the {@link #end end} method is always
  * invoked, these methods should be used within a
- * <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block:
+ * {@code try}&nbsp;...&nbsp;{@code finally} block:
  *
- * <blockquote><pre>
+ * <blockquote><pre id="be">
  * try {
  *     begin();
  *     // Perform blocking I/O operation here
@@ -70,7 +70,7 @@
     extends Selector
 {
 
-    private AtomicBoolean selectorOpen = new AtomicBoolean(true);
+    private final AtomicBoolean selectorOpen = new AtomicBoolean(true);
 
     // The provider that created this selector
     private final SelectorProvider provider;
@@ -197,7 +197,7 @@
      * Marks the beginning of an I/O operation that might block indefinitely.
      *
      * <p> This method should be invoked in tandem with the {@link #end end}
-     * method, using a <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block as
+     * method, using a {@code try}&nbsp;...&nbsp;{@code finally} block as
      * shown <a href="#be">above</a>, in order to implement interruption for
      * this selector.
      *
@@ -223,7 +223,7 @@
      * Marks the end of an I/O operation that might block indefinitely.
      *
      * <p> This method should be invoked in tandem with the {@link #begin begin}
-     * method, using a <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block as
+     * method, using a {@code try}&nbsp;...&nbsp;{@code finally} block as
      * shown <a href="#be">above</a>, in order to implement interruption for
      * this selector.  </p>
      */
diff --git a/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java b/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java
index 464b4fc..6a77d3d 100644
--- a/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java
+++ b/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java
@@ -64,7 +64,7 @@
      *
      * @throws  SecurityException
      *          If a security manager has been installed and it denies
-     *          {@link RuntimePermission}<tt>("asynchronousChannelProvider")</tt>
+     *          {@link RuntimePermission}{@code ("asynchronousChannelProvider")}
      */
     protected AsynchronousChannelProvider() {
         this(checkPermission());
@@ -76,7 +76,7 @@
 
         private static AsynchronousChannelProvider load() {
             return AccessController
-                .doPrivileged(new PrivilegedAction<AsynchronousChannelProvider>() {
+                .doPrivileged(new PrivilegedAction<>() {
                     public AsynchronousChannelProvider run() {
                         AsynchronousChannelProvider p;
                         p = loadProviderFromProperty();
@@ -94,9 +94,10 @@
             if (cn == null)
                 return null;
             try {
-                Class<?> c = Class.forName(cn, true,
-                                           ClassLoader.getSystemClassLoader());
-                return (AsynchronousChannelProvider)c.newInstance();
+                @SuppressWarnings("deprecation")
+                Object tmp = Class.forName(cn, true,
+                                           ClassLoader.getSystemClassLoader()).newInstance();
+                return (AsynchronousChannelProvider)tmp;
             } catch (ClassNotFoundException x) {
                 throw new ServiceConfigurationError(null, x);
             } catch (IllegalAccessException x) {
@@ -137,7 +138,7 @@
      * <ol>
      *
      *   <li><p> If the system property
-     *   <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> is defined
+     *   {@code java.nio.channels.spi.AsynchronousChannelProvider} is defined
      *   then it is taken to be the fully-qualified name of a concrete provider class.
      *   The class is loaded and instantiated; if this process fails then an
      *   unspecified error is thrown.  </p></li>
@@ -145,8 +146,8 @@
      *   <li><p> If a provider class has been installed in a jar file that is
      *   visible to the system class loader, and that jar file contains a
      *   provider-configuration file named
-     *   <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> in the resource
-     *   directory <tt>META-INF/services</tt>, then the first class name
+     *   {@code java.nio.channels.spi.AsynchronousChannelProvider} in the resource
+     *   directory {@code META-INF/services}, then the first class name
      *   specified in that file is taken.  The class is loaded and
      *   instantiated; if this process fails then an unspecified error is
      *   thrown.  </p></li>
diff --git a/ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java b/ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java
index 2dbef05..c162eed 100644
--- a/ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java
+++ b/ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java
@@ -46,7 +46,7 @@
  * #provider() provider} method.  The first invocation of that method will locate
  * the default provider as specified below.
  *
- * <p> The system-wide default provider is used by the static <tt>open</tt>
+ * <p> The system-wide default provider is used by the static {@code open}
  * methods of the {@link java.nio.channels.DatagramChannel#open
  * DatagramChannel}, {@link java.nio.channels.Pipe#open Pipe}, {@link
  * java.nio.channels.Selector#open Selector}, {@link
@@ -54,7 +54,7 @@
  * java.nio.channels.SocketChannel#open SocketChannel} classes.  It is also
  * used by the {@link java.lang.System#inheritedChannel System.inheritedChannel()}
  * method. A program may make use of a provider other than the default provider
- * by instantiating that provider and then directly invoking the <tt>open</tt>
+ * by instantiating that provider and then directly invoking the {@code open}
  * methods defined in this class.
  *
  * <p> All of the methods in this class are safe for use by multiple concurrent
@@ -71,17 +71,23 @@
     private static final Object lock = new Object();
     private static SelectorProvider provider = null;
 
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("selectorProvider"));
+        return null;
+    }
+    private SelectorProvider(Void ignore) { }
+
     /**
      * Initializes a new instance of this class.
      *
      * @throws  SecurityException
      *          If a security manager has been installed and it denies
-     *          {@link RuntimePermission}<tt>("selectorProvider")</tt>
+     *          {@link RuntimePermission}{@code ("selectorProvider")}
      */
     protected SelectorProvider() {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null)
-            sm.checkPermission(new RuntimePermission("selectorProvider"));
+        this(checkPermission());
     }
 
     private static boolean loadProviderFromProperty() {
@@ -89,9 +95,10 @@
         if (cn == null)
             return false;
         try {
-            Class<?> c = Class.forName(cn, true,
-                                       ClassLoader.getSystemClassLoader());
-            provider = (SelectorProvider)c.newInstance();
+            @SuppressWarnings("deprecation")
+            Object tmp = Class.forName(cn, true,
+                                       ClassLoader.getSystemClassLoader()).newInstance();
+            provider = (SelectorProvider)tmp;
             return true;
         } catch (ClassNotFoundException x) {
             throw new ServiceConfigurationError(null, x);
@@ -136,7 +143,7 @@
      * <ol>
      *
      *   <li><p> If the system property
-     *   <tt>java.nio.channels.spi.SelectorProvider</tt> is defined then it is
+     *   {@code java.nio.channels.spi.SelectorProvider} is defined then it is
      *   taken to be the fully-qualified name of a concrete provider class.
      *   The class is loaded and instantiated; if this process fails then an
      *   unspecified error is thrown.  </p></li>
@@ -144,8 +151,8 @@
      *   <li><p> If a provider class has been installed in a jar file that is
      *   visible to the system class loader, and that jar file contains a
      *   provider-configuration file named
-     *   <tt>java.nio.channels.spi.SelectorProvider</tt> in the resource
-     *   directory <tt>META-INF/services</tt>, then the first class name
+     *   {@code java.nio.channels.spi.SelectorProvider} in the resource
+     *   directory {@code META-INF/services}, then the first class name
      *   specified in that file is taken.  The class is loaded and
      *   instantiated; if this process fails then an unspecified error is
      *   thrown.  </p></li>
@@ -166,7 +173,7 @@
             if (provider != null)
                 return provider;
             return AccessController.doPrivileged(
-                new PrivilegedAction<SelectorProvider>() {
+                new PrivilegedAction<>() {
                     public SelectorProvider run() {
                             if (loadProviderFromProperty())
                                 return provider;
@@ -299,14 +306,14 @@
      * returned. Subsequent invocations of this method return the same
      * channel. </p>
      *
-     * @return  The inherited channel, if any, otherwise <tt>null</tt>.
+     * @return  The inherited channel, if any, otherwise {@code null}.
      *
      * @throws  IOException
      *          If an I/O error occurs
      *
      * @throws  SecurityException
      *          If a security manager has been installed and it denies
-     *          {@link RuntimePermission}<tt>("inheritedChannel")</tt>
+     *          {@link RuntimePermission}{@code ("inheritedChannel")}
      *
      * @since 1.5
      */
diff --git a/ojluni/src/main/java/java/nio/file/FileStore.java b/ojluni/src/main/java/java/nio/file/FileStore.java
index 2b14a4b..06d4f11 100644
--- a/ojluni/src/main/java/java/nio/file/FileStore.java
+++ b/ojluni/src/main/java/java/nio/file/FileStore.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -112,6 +112,31 @@
     public abstract long getUsableSpace() throws IOException;
 
     /**
+     * Returns the number of bytes per block in this file store.
+     *
+     * <p> File storage is typically organized into discrete sequences of bytes
+     * called <i>blocks</i>. A block is the smallest storage unit of a file store.
+     * Every read and write operation is performed on a multiple of blocks.
+     *
+     * @implSpec The implementation in this class throws an
+     *         {@code UnsupportedOperationException}.
+     *
+     * @return  a positive value representing the block size of this file store,
+     *          in bytes
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     *
+     * @throws  UnsupportedOperationException
+     *          if the operation is not supported
+     *
+     * @since 10
+     */
+    public long getBlockSize() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
      * Returns the number of unallocated bytes in the file store.
      *
      * <p> The returned number of unallocated bytes is a hint, but not a
@@ -208,7 +233,7 @@
      * @param   attribute
      *          the attribute to read
 
-     * @return  the attribute value; {@code null} may be a valid valid for some
+     * @return  the attribute value; {@code null} may be valid for some
      *          attributes
      *
      * @throws  UnsupportedOperationException
diff --git a/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java b/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java
new file mode 100644
index 0000000..d8b0548
--- /dev/null
+++ b/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.security.cert;
+
+import java.net.URI;
+
+/**
+ * Parameters used as input for {@code CertStore} algorithms which use
+ * information contained in a URI to retrieve certificates and CRLs.
+ * <p>
+ * This class is used to provide necessary configuration parameters
+ * through a URI as defined in RFC 5280 to implementations of
+ * {@code CertStore} algorithms.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @since       9
+ * @see         CertStore
+ * @see         java.net.URI
+ */
+public final class URICertStoreParameters implements CertStoreParameters {
+
+    /**
+     * The uri, cannot be null
+     */
+    private final URI uri;
+
+    /*
+     * Hash code for this parameters.
+     */
+    private int myhash = -1;
+
+    /**
+     * Creates an instance of {@code URICertStoreParameters} with the
+     * specified URI.
+     *
+     * @param uri the URI which contains configuration information.
+     * @throws NullPointerException if {@code uri} is null
+     */
+    public URICertStoreParameters(URI uri) {
+        if (uri == null) {
+            throw new NullPointerException();
+        }
+        this.uri = uri;
+    }
+
+    /**
+     * Returns the URI used to construct this
+     * {@code URICertStoreParameters} object.
+     *
+     * @return the URI.
+     */
+    public URI getURI() {
+        return uri;
+    }
+
+    /**
+     * Returns a copy of this object. Changes to the copy will not affect
+     * the original and vice versa.
+     *
+     * @return the copy
+     */
+    @Override
+    public URICertStoreParameters clone() {
+        try {
+            return new URICertStoreParameters(uri);
+        } catch (NullPointerException e) {
+            /* Cannot happen */
+            throw new InternalError(e.toString(), e);
+        }
+    }
+
+    /**
+     * Returns a hash code value for this parameters object.
+     * The hash code is generated using the URI supplied at construction.
+     *
+     * @return a hash code value for this parameters.
+     */
+    @Override
+    public int hashCode() {
+        if (myhash == -1) {
+            myhash = uri.hashCode()*7;
+        }
+        return myhash;
+    }
+
+    /**
+     * Compares the specified object with this parameters object for equality.
+     * Two URICertStoreParameters are considered equal if the URIs used
+     * to construct them are equal.
+     *
+     * @param p the object to test for equality with this parameters.
+     *
+     * @return true if the specified object is equal to this parameters object.
+     */
+    @Override
+    public boolean equals(Object p) {
+        if (p == null || (!(p instanceof URICertStoreParameters))) {
+            return false;
+        }
+
+        if (p == this) {
+            return true;
+        }
+
+        URICertStoreParameters other = (URICertStoreParameters)p;
+        return uri.equals(other.getURI());
+    }
+
+    /**
+     * Returns a formatted string describing the parameters
+     * including the URI used to construct this object.
+     *
+     * @return a formatted string describing the parameters
+     */
+    @Override
+    public String toString() {
+        return "URICertStoreParameters: " + uri.toString();
+    }
+}
diff --git a/ojluni/src/main/java/java/util/Arrays.java b/ojluni/src/main/java/java/util/Arrays.java
index 8cd8aaf..05a0893 100644
--- a/ojluni/src/main/java/java/util/Arrays.java
+++ b/ojluni/src/main/java/java/util/Arrays.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, 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
@@ -26,6 +26,9 @@
 
 package java.util;
 
+import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.util.ArraysSupport;
+
 import java.lang.reflect.Array;
 import java.util.concurrent.ForkJoinPool;
 import java.util.function.BinaryOperator;
@@ -53,7 +56,7 @@
  * if the specified array reference is null, except where noted.
  *
  * <p>The documentation for the methods contained in this class includes
- * briefs description of the <i>implementations</i>. Such descriptions should
+ * brief descriptions of the <i>implementations</i>. Such descriptions should
  * be regarded as <i>implementation notes</i>, rather than parts of the
  * <i>specification</i>. Implementors should feel free to substitute other
  * algorithms, so long as the specification itself is adhered to. (For
@@ -61,7 +64,7 @@
  * a MergeSort, but it does have to be <i>stable</i>.)
  *
  * <p>This class is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
  * Java Collections Framework</a>.
  *
  * @author Josh Bloch
@@ -111,7 +114,7 @@
      * Checks that {@code fromIndex} and {@code toIndex} are in
      * the range and throws an exception if they aren't.
      */
-    private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
+    static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
         if (fromIndex > toIndex) {
             throw new IllegalArgumentException(
                     "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
@@ -1007,7 +1010,7 @@
             (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
             TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0);
         else
-            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+            new ArraysParallelSortHelpers.FJObject.Sorter<>
                 (null, a,
                  (T[])Array.newInstance(a.getClass().getComponentType(), n),
                  0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
@@ -1066,7 +1069,7 @@
             (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
             TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0);
         else
-            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+            new ArraysParallelSortHelpers.FJObject.Sorter<>
                 (null, a,
                  (T[])Array.newInstance(a.getClass().getComponentType(), n),
                  fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
@@ -1115,7 +1118,7 @@
             (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
             TimSort.sort(a, 0, n, cmp, null, 0, 0);
         else
-            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+            new ArraysParallelSortHelpers.FJObject.Sorter<>
                 (null, a,
                  (T[])Array.newInstance(a.getClass().getComponentType(), n),
                  0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
@@ -1176,7 +1179,7 @@
             (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
             TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0);
         else
-            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+            new ArraysParallelSortHelpers.FJObject.Sorter<>
                 (null, a,
                  (T[])Array.newInstance(a.getClass().getComponentType(), n),
                  fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
@@ -1213,7 +1216,7 @@
      *
      * <p>The implementation takes equal advantage of ascending and
      * descending order in its input array, and can take advantage of
-     * ascending and descending order in different parts of the the same
+     * ascending and descending order in different parts of the same
      * input array.  It is well-suited to merging two or more sorted arrays:
      * simply concatenate the arrays and sort the resulting array.
      *
@@ -1269,7 +1272,7 @@
      *
      * <p>The implementation takes equal advantage of ascending and
      * descending order in its input array, and can take advantage of
-     * ascending and descending order in different parts of the the same
+     * ascending and descending order in different parts of the same
      * input array.  It is well-suited to merging two or more sorted arrays:
      * simply concatenate the arrays and sort the resulting array.
      *
@@ -1392,7 +1395,7 @@
      *
      * <p>The implementation takes equal advantage of ascending and
      * descending order in its input array, and can take advantage of
-     * ascending and descending order in different parts of the the same
+     * ascending and descending order in different parts of the same
      * input array.  It is well-suited to merging two or more sorted arrays:
      * simply concatenate the arrays and sort the resulting array.
      *
@@ -1452,7 +1455,7 @@
      *
      * <p>The implementation takes equal advantage of ascending and
      * descending order in its input array, and can take advantage of
-     * ascending and descending order in different parts of the the same
+     * ascending and descending order in different parts of the same
      * input array.  It is well-suited to merging two or more sorted arrays:
      * simply concatenate the arrays and sort the resulting array.
      *
@@ -1696,10 +1699,10 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -1726,11 +1729,11 @@
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -1777,10 +1780,10 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -1807,11 +1810,11 @@
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -1858,10 +1861,10 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -1888,11 +1891,11 @@
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -1939,10 +1942,10 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -1969,11 +1972,11 @@
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2020,10 +2023,10 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2050,11 +2053,11 @@
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2102,10 +2105,10 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2133,11 +2136,11 @@
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2193,10 +2196,10 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key. Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2224,11 +2227,11 @@
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key. Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2290,10 +2293,10 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2328,11 +2331,11 @@
      * @param key the value to be searched for
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2388,13 +2391,13 @@
      * @param a the array to be searched
      * @param key the value to be searched for
      * @param c the comparator by which the array is ordered.  A
-     *        <tt>null</tt> value indicates that the elements'
+     *        {@code null} value indicates that the elements'
      *        {@linkplain Comparable natural ordering} should be used.
      * @return index of the search key, if it is contained in the array;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
-     *         element greater than the key, or <tt>a.length</tt> if all
+     *         element greater than the key, or {@code a.length} if all
      *         elements in the array are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2427,15 +2430,15 @@
      * @param toIndex the index of the last element (exclusive) to be searched
      * @param key the value to be searched for
      * @param c the comparator by which the array is ordered.  A
-     *        <tt>null</tt> value indicates that the elements'
+     *        {@code null} value indicates that the elements'
      *        {@linkplain Comparable natural ordering} should be used.
      * @return index of the search key, if it is contained in the array
      *         within the specified range;
-     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
      *         <i>insertion point</i> is defined as the point at which the
      *         key would be inserted into the array: the index of the first
      *         element in the range greater than the key,
-     *         or <tt>toIndex</tt> if all
+     *         or {@code toIndex} if all
      *         elements in the range are less than the specified key.  Note
      *         that this guarantees that the return value will be &gt;= 0 if
      *         and only if the key is found.
@@ -2481,16 +2484,16 @@
     // Equality Testing
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of longs are
+     * Returns {@code true} if the two specified arrays of longs are
      * <i>equal</i> to one another.  Two arrays are considered equal if both
      * arrays contain the same number of elements, and all corresponding pairs
      * of elements in the two arrays are equal.  In other words, two arrays
      * are equal if they contain the same elements in the same order.  Also,
-     * two array references are considered equal if both are <tt>null</tt>.<p>
+     * two array references are considered equal if both are {@code null}.
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      */
     public static boolean equals(long[] a, long[] a2) {
         if (a==a2)
@@ -2502,24 +2505,67 @@
         if (a2.length != length)
             return false;
 
-        for (int i=0; i<length; i++)
-            if (a[i] != a2[i])
-                return false;
-
-        return true;
+        return ArraysSupport.mismatch(a, a2, length) < 0;
     }
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of ints are
+     * Returns true if the two specified arrays of longs, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(long[] a, int aFromIndex, int aToIndex,
+                                 long[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of ints are
      * <i>equal</i> to one another.  Two arrays are considered equal if both
      * arrays contain the same number of elements, and all corresponding pairs
      * of elements in the two arrays are equal.  In other words, two arrays
      * are equal if they contain the same elements in the same order.  Also,
-     * two array references are considered equal if both are <tt>null</tt>.<p>
+     * two array references are considered equal if both are {@code null}.
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      */
     public static boolean equals(int[] a, int[] a2) {
         if (a==a2)
@@ -2531,24 +2577,67 @@
         if (a2.length != length)
             return false;
 
-        for (int i=0; i<length; i++)
-            if (a[i] != a2[i])
-                return false;
-
-        return true;
+        return ArraysSupport.mismatch(a, a2, length) < 0;
     }
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of shorts are
+     * Returns true if the two specified arrays of ints, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(int[] a, int aFromIndex, int aToIndex,
+                                 int[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of shorts are
      * <i>equal</i> to one another.  Two arrays are considered equal if both
      * arrays contain the same number of elements, and all corresponding pairs
      * of elements in the two arrays are equal.  In other words, two arrays
      * are equal if they contain the same elements in the same order.  Also,
-     * two array references are considered equal if both are <tt>null</tt>.<p>
+     * two array references are considered equal if both are {@code null}.
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      */
     public static boolean equals(short[] a, short a2[]) {
         if (a==a2)
@@ -2560,25 +2649,69 @@
         if (a2.length != length)
             return false;
 
-        for (int i=0; i<length; i++)
-            if (a[i] != a2[i])
-                return false;
-
-        return true;
+        return ArraysSupport.mismatch(a, a2, length) < 0;
     }
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of chars are
+     * Returns true if the two specified arrays of shorts, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(short[] a, int aFromIndex, int aToIndex,
+                                 short[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of chars are
      * <i>equal</i> to one another.  Two arrays are considered equal if both
      * arrays contain the same number of elements, and all corresponding pairs
      * of elements in the two arrays are equal.  In other words, two arrays
      * are equal if they contain the same elements in the same order.  Also,
-     * two array references are considered equal if both are <tt>null</tt>.<p>
+     * two array references are considered equal if both are {@code null}.
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      */
+    @HotSpotIntrinsicCandidate
     public static boolean equals(char[] a, char[] a2) {
         if (a==a2)
             return true;
@@ -2589,25 +2722,69 @@
         if (a2.length != length)
             return false;
 
-        for (int i=0; i<length; i++)
-            if (a[i] != a2[i])
-                return false;
-
-        return true;
+        return ArraysSupport.mismatch(a, a2, length) < 0;
     }
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of bytes are
+     * Returns true if the two specified arrays of chars, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(char[] a, int aFromIndex, int aToIndex,
+                                 char[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of bytes are
      * <i>equal</i> to one another.  Two arrays are considered equal if both
      * arrays contain the same number of elements, and all corresponding pairs
      * of elements in the two arrays are equal.  In other words, two arrays
      * are equal if they contain the same elements in the same order.  Also,
-     * two array references are considered equal if both are <tt>null</tt>.<p>
+     * two array references are considered equal if both are {@code null}.
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      */
+    @HotSpotIntrinsicCandidate
     public static boolean equals(byte[] a, byte[] a2) {
         if (a==a2)
             return true;
@@ -2618,24 +2795,67 @@
         if (a2.length != length)
             return false;
 
-        for (int i=0; i<length; i++)
-            if (a[i] != a2[i])
-                return false;
-
-        return true;
+        return ArraysSupport.mismatch(a, a2, length) < 0;
     }
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of booleans are
+     * Returns true if the two specified arrays of bytes, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(byte[] a, int aFromIndex, int aToIndex,
+                                 byte[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of booleans are
      * <i>equal</i> to one another.  Two arrays are considered equal if both
      * arrays contain the same number of elements, and all corresponding pairs
      * of elements in the two arrays are equal.  In other words, two arrays
      * are equal if they contain the same elements in the same order.  Also,
-     * two array references are considered equal if both are <tt>null</tt>.<p>
+     * two array references are considered equal if both are {@code null}.
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      */
     public static boolean equals(boolean[] a, boolean[] a2) {
         if (a==a2)
@@ -2647,29 +2867,72 @@
         if (a2.length != length)
             return false;
 
-        for (int i=0; i<length; i++)
-            if (a[i] != a2[i])
-                return false;
-
-        return true;
+        return ArraysSupport.mismatch(a, a2, length) < 0;
     }
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of doubles are
+     * Returns true if the two specified arrays of booleans, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(boolean[] a, int aFromIndex, int aToIndex,
+                                 boolean[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of doubles are
      * <i>equal</i> to one another.  Two arrays are considered equal if both
      * arrays contain the same number of elements, and all corresponding pairs
      * of elements in the two arrays are equal.  In other words, two arrays
      * are equal if they contain the same elements in the same order.  Also,
-     * two array references are considered equal if both are <tt>null</tt>.<p>
+     * two array references are considered equal if both are {@code null}.
      *
-     * Two doubles <tt>d1</tt> and <tt>d2</tt> are considered equal if:
-     * <pre>    <tt>new Double(d1).equals(new Double(d2))</tt></pre>
-     * (Unlike the <tt>==</tt> operator, this method considers
-     * <tt>NaN</tt> equals to itself, and 0.0d unequal to -0.0d.)
+     * Two doubles {@code d1} and {@code d2} are considered equal if:
+     * <pre>    {@code new Double(d1).equals(new Double(d2))}</pre>
+     * (Unlike the {@code ==} operator, this method considers
+     * {@code NaN} equals to itself, and 0.0d unequal to -0.0d.)
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      * @see Double#equals(Object)
      */
     public static boolean equals(double[] a, double[] a2) {
@@ -2682,29 +2945,77 @@
         if (a2.length != length)
             return false;
 
-        for (int i=0; i<length; i++)
-            if (Double.doubleToLongBits(a[i])!=Double.doubleToLongBits(a2[i]))
-                return false;
-
-        return true;
+        return ArraysSupport.mismatch(a, a2, length) < 0;
     }
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of floats are
+     * Returns true if the two specified arrays of doubles, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * <p>Two doubles {@code d1} and {@code d2} are considered equal if:
+     * <pre>    {@code new Double(d1).equals(new Double(d2))}</pre>
+     * (Unlike the {@code ==} operator, this method considers
+     * {@code NaN} equals to itself, and 0.0d unequal to -0.0d.)
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @see Double#equals(Object)
+     * @since 9
+     */
+    public static boolean equals(double[] a, int aFromIndex, int aToIndex,
+                                 double[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex, aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of floats are
      * <i>equal</i> to one another.  Two arrays are considered equal if both
      * arrays contain the same number of elements, and all corresponding pairs
      * of elements in the two arrays are equal.  In other words, two arrays
      * are equal if they contain the same elements in the same order.  Also,
-     * two array references are considered equal if both are <tt>null</tt>.<p>
+     * two array references are considered equal if both are {@code null}.
      *
-     * Two floats <tt>f1</tt> and <tt>f2</tt> are considered equal if:
-     * <pre>    <tt>new Float(f1).equals(new Float(f2))</tt></pre>
-     * (Unlike the <tt>==</tt> operator, this method considers
-     * <tt>NaN</tt> equals to itself, and 0.0f unequal to -0.0f.)
+     * Two floats {@code f1} and {@code f2} are considered equal if:
+     * <pre>    {@code new Float(f1).equals(new Float(f2))}</pre>
+     * (Unlike the {@code ==} operator, this method considers
+     * {@code NaN} equals to itself, and 0.0f unequal to -0.0f.)
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      * @see Float#equals(Object)
      */
     public static boolean equals(float[] a, float[] a2) {
@@ -2717,26 +3028,75 @@
         if (a2.length != length)
             return false;
 
-        for (int i=0; i<length; i++)
-            if (Float.floatToIntBits(a[i])!=Float.floatToIntBits(a2[i]))
-                return false;
-
-        return true;
+        return ArraysSupport.mismatch(a, a2, length) < 0;
     }
 
     /**
-     * Returns <tt>true</tt> if the two specified arrays of Objects are
+     * Returns true if the two specified arrays of floats, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * <p>Two floats {@code f1} and {@code f2} are considered equal if:
+     * <pre>    {@code new Float(f1).equals(new Float(f2))}</pre>
+     * (Unlike the {@code ==} operator, this method considers
+     * {@code NaN} equals to itself, and 0.0f unequal to -0.0f.)
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @see Float#equals(Object)
+     * @since 9
+     */
+    public static boolean equals(float[] a, int aFromIndex, int aToIndex,
+                                 float[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex, aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of Objects are
      * <i>equal</i> to one another.  The two arrays are considered equal if
      * both arrays contain the same number of elements, and all corresponding
-     * pairs of elements in the two arrays are equal.  Two objects <tt>e1</tt>
-     * and <tt>e2</tt> are considered <i>equal</i> if <tt>(e1==null ? e2==null
-     * : e1.equals(e2))</tt>.  In other words, the two arrays are equal if
+     * pairs of elements in the two arrays are equal.  Two objects {@code e1}
+     * and {@code e2} are considered <i>equal</i> if
+     * {@code Objects.equals(e1, e2)}.
+     * In other words, the two arrays are equal if
      * they contain the same elements in the same order.  Also, two array
-     * references are considered equal if both are <tt>null</tt>.<p>
+     * references are considered equal if both are {@code null}.
      *
      * @param a one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      */
     public static boolean equals(Object[] a, Object[] a2) {
         if (a==a2)
@@ -2749,9 +3109,157 @@
             return false;
 
         for (int i=0; i<length; i++) {
-            Object o1 = a[i];
-            Object o2 = a2[i];
-            if (!(o1==null ? o2==null : o1.equals(o2)))
+            if (!Objects.equals(a[i], a2[i]))
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns true if the two specified arrays of Objects, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if
+     * {@code Objects.equals(e1, e2)}.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(Object[] a, int aFromIndex, int aToIndex,
+                                 Object[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        for (int i = 0; i < aLength; i++) {
+            if (!Objects.equals(a[aFromIndex++], b[bFromIndex++]))
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of Objects are
+     * <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if both arrays contain the same number
+     * of elements, and all corresponding pairs of elements in the two arrays
+     * are equal.  In other words, the two arrays are equal if they contain the
+     * same elements in the same order.  Also, two array references are
+     * considered equal if both are {@code null}.
+     *
+     * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if,
+     * given the specified comparator, {@code cmp.compare(e1, e2) == 0}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return {@code true} if the two arrays are equal
+     * @throws NullPointerException if the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> boolean equals(T[] a, T[] a2, Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++) {
+            if (cmp.compare(a[i], a2[i]) != 0)
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns true if the two specified arrays of Objects, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if,
+     * given the specified comparator, {@code cmp.compare(e1, e2) == 0}.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested fro equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array or the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> boolean equals(T[] a, int aFromIndex, int aToIndex,
+                                     T[] b, int bFromIndex, int bToIndex,
+                                     Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        for (int i = 0; i < aLength; i++) {
+            if (cmp.compare(a[aFromIndex++], b[bFromIndex++]) != 0)
                 return false;
         }
 
@@ -2775,8 +3283,8 @@
     /**
      * Assigns the specified long value to each element of the specified
      * range of the specified array of longs.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -2785,9 +3293,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      */
     public static void fill(long[] a, int fromIndex, int toIndex, long val) {
         rangeCheck(a.length, fromIndex, toIndex);
@@ -2810,8 +3318,8 @@
     /**
      * Assigns the specified int value to each element of the specified
      * range of the specified array of ints.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -2820,9 +3328,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      */
     public static void fill(int[] a, int fromIndex, int toIndex, int val) {
         rangeCheck(a.length, fromIndex, toIndex);
@@ -2845,8 +3353,8 @@
     /**
      * Assigns the specified short value to each element of the specified
      * range of the specified array of shorts.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -2855,9 +3363,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      */
     public static void fill(short[] a, int fromIndex, int toIndex, short val) {
         rangeCheck(a.length, fromIndex, toIndex);
@@ -2880,8 +3388,8 @@
     /**
      * Assigns the specified char value to each element of the specified
      * range of the specified array of chars.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -2890,9 +3398,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      */
     public static void fill(char[] a, int fromIndex, int toIndex, char val) {
         rangeCheck(a.length, fromIndex, toIndex);
@@ -2915,8 +3423,8 @@
     /**
      * Assigns the specified byte value to each element of the specified
      * range of the specified array of bytes.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -2925,9 +3433,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      */
     public static void fill(byte[] a, int fromIndex, int toIndex, byte val) {
         rangeCheck(a.length, fromIndex, toIndex);
@@ -2950,8 +3458,8 @@
     /**
      * Assigns the specified boolean value to each element of the specified
      * range of the specified array of booleans.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -2960,9 +3468,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      */
     public static void fill(boolean[] a, int fromIndex, int toIndex,
                             boolean val) {
@@ -2986,8 +3494,8 @@
     /**
      * Assigns the specified double value to each element of the specified
      * range of the specified array of doubles.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -2996,9 +3504,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      */
     public static void fill(double[] a, int fromIndex, int toIndex,double val){
         rangeCheck(a.length, fromIndex, toIndex);
@@ -3021,8 +3529,8 @@
     /**
      * Assigns the specified float value to each element of the specified
      * range of the specified array of floats.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -3031,9 +3539,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      */
     public static void fill(float[] a, int fromIndex, int toIndex, float val) {
         rangeCheck(a.length, fromIndex, toIndex);
@@ -3058,8 +3566,8 @@
     /**
      * Assigns the specified Object reference to each element of the specified
      * range of the specified array of Objects.  The range to be filled
-     * extends from index <tt>fromIndex</tt>, inclusive, to index
-     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
      * range to be filled is empty.)
      *
      * @param a the array to be filled
@@ -3068,9 +3576,9 @@
      * @param toIndex the index of the last element (exclusive) to be
      *        filled with the specified value
      * @param val the value to be stored in all elements of the array
-     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
-     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
-     *         <tt>toIndex &gt; a.length</tt>
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
      * @throws ArrayStoreException if the specified value is not of a
      *         runtime type that can be stored in the specified array
      */
@@ -3087,7 +3595,7 @@
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>null</tt>.
+     * copy but not the original, the copy will contain {@code null}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
      * The resulting array is of exactly the same class as the original array.
@@ -3097,8 +3605,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with nulls
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     @SuppressWarnings("unchecked")
@@ -3111,10 +3619,10 @@
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>null</tt>.
+     * copy but not the original, the copy will contain {@code null}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
-     * The resulting array is of the class <tt>newType</tt>.
+     * The resulting array is of the class {@code newType}.
      *
      * @param <U> the class of the objects in the original array
      * @param <T> the class of the objects in the returned array
@@ -3123,13 +3631,14 @@
      * @param newType the class of the copy to be returned
      * @return a copy of the original array, truncated or padded with nulls
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @throws ArrayStoreException if an element copied from
-     *     <tt>original</tt> is not of a runtime type that can be stored in
-     *     an array of class <tt>newType</tt>
+     *     {@code original} is not of a runtime type that can be stored in
+     *     an array of class {@code newType}
      * @since 1.6
      */
+    @HotSpotIntrinsicCandidate
     public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
         @SuppressWarnings("unchecked")
         T[] copy = ((Object)newType == (Object)Object[].class)
@@ -3145,7 +3654,7 @@
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>(byte)0</tt>.
+     * copy but not the original, the copy will contain {@code (byte)0}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
      *
@@ -3153,8 +3662,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with zeros
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static byte[] copyOf(byte[] original, int newLength) {
@@ -3169,7 +3678,7 @@
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>(short)0</tt>.
+     * copy but not the original, the copy will contain {@code (short)0}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
      *
@@ -3177,8 +3686,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with zeros
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static short[] copyOf(short[] original, int newLength) {
@@ -3193,7 +3702,7 @@
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>0</tt>.
+     * copy but not the original, the copy will contain {@code 0}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
      *
@@ -3201,8 +3710,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with zeros
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static int[] copyOf(int[] original, int newLength) {
@@ -3217,7 +3726,7 @@
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>0L</tt>.
+     * copy but not the original, the copy will contain {@code 0L}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
      *
@@ -3225,8 +3734,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with zeros
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static long[] copyOf(long[] original, int newLength) {
@@ -3241,7 +3750,7 @@
      * so the copy has the specified length.  For all indices that are valid
      * in both the original array and the copy, the two arrays will contain
      * identical values.  For any indices that are valid in the copy but not
-     * the original, the copy will contain <tt>'\\u000'</tt>.  Such indices
+     * the original, the copy will contain {@code '\\u000'}.  Such indices
      * will exist if and only if the specified length is greater than that of
      * the original array.
      *
@@ -3249,8 +3758,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with null characters
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static char[] copyOf(char[] original, int newLength) {
@@ -3265,7 +3774,7 @@
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>0f</tt>.
+     * copy but not the original, the copy will contain {@code 0f}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
      *
@@ -3273,8 +3782,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with zeros
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static float[] copyOf(float[] original, int newLength) {
@@ -3289,7 +3798,7 @@
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>0d</tt>.
+     * copy but not the original, the copy will contain {@code 0d}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
      *
@@ -3297,8 +3806,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with zeros
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static double[] copyOf(double[] original, int newLength) {
@@ -3309,11 +3818,11 @@
     }
 
     /**
-     * Copies the specified array, truncating or padding with <tt>false</tt> (if necessary)
+     * Copies the specified array, truncating or padding with {@code false} (if necessary)
      * so the copy has the specified length.  For all indices that are
      * valid in both the original array and the copy, the two arrays will
      * contain identical values.  For any indices that are valid in the
-     * copy but not the original, the copy will contain <tt>false</tt>.
+     * copy but not the original, the copy will contain {@code false}.
      * Such indices will exist if and only if the specified length
      * is greater than that of the original array.
      *
@@ -3321,8 +3830,8 @@
      * @param newLength the length of the copy to be returned
      * @return a copy of the original array, truncated or padded with false elements
      *     to obtain the specified length
-     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static boolean[] copyOf(boolean[] original, int newLength) {
@@ -3334,17 +3843,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>null</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code null} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      * <p>
      * The resulting array is of exactly the same class as the original array.
      *
@@ -3357,8 +3866,8 @@
      *     truncated or padded with nulls to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     @SuppressWarnings("unchecked")
@@ -3368,18 +3877,18 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>null</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
-     * The resulting array is of the class <tt>newType</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code null} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     * The resulting array is of the class {@code newType}.
      *
      * @param <U> the class of the objects in the original array
      * @param <T> the class of the objects in the returned array
@@ -3392,13 +3901,14 @@
      *     truncated or padded with nulls to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @throws ArrayStoreException if an element copied from
-     *     <tt>original</tt> is not of a runtime type that can be stored in
-     *     an array of class <tt>newType</tt>.
+     *     {@code original} is not of a runtime type that can be stored in
+     *     an array of class {@code newType}.
      * @since 1.6
      */
+    @HotSpotIntrinsicCandidate
     public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
         int newLength = to - from;
         if (newLength < 0)
@@ -3414,17 +3924,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>(byte)0</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code (byte)0} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      *
      * @param original the array from which a range is to be copied
      * @param from the initial index of the range to be copied, inclusive
@@ -3434,8 +3944,8 @@
      *     truncated or padded with zeros to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static byte[] copyOfRange(byte[] original, int from, int to) {
@@ -3450,17 +3960,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>(short)0</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code (short)0} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      *
      * @param original the array from which a range is to be copied
      * @param from the initial index of the range to be copied, inclusive
@@ -3470,8 +3980,8 @@
      *     truncated or padded with zeros to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static short[] copyOfRange(short[] original, int from, int to) {
@@ -3486,17 +3996,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>0</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code 0} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      *
      * @param original the array from which a range is to be copied
      * @param from the initial index of the range to be copied, inclusive
@@ -3506,8 +4016,8 @@
      *     truncated or padded with zeros to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static int[] copyOfRange(int[] original, int from, int to) {
@@ -3522,17 +4032,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>0L</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code 0L} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      *
      * @param original the array from which a range is to be copied
      * @param from the initial index of the range to be copied, inclusive
@@ -3542,8 +4052,8 @@
      *     truncated or padded with zeros to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static long[] copyOfRange(long[] original, int from, int to) {
@@ -3558,17 +4068,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>'\\u000'</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code '\\u000'} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      *
      * @param original the array from which a range is to be copied
      * @param from the initial index of the range to be copied, inclusive
@@ -3578,8 +4088,8 @@
      *     truncated or padded with null characters to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static char[] copyOfRange(char[] original, int from, int to) {
@@ -3594,17 +4104,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>0f</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code 0f} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      *
      * @param original the array from which a range is to be copied
      * @param from the initial index of the range to be copied, inclusive
@@ -3614,8 +4124,8 @@
      *     truncated or padded with zeros to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static float[] copyOfRange(float[] original, int from, int to) {
@@ -3630,17 +4140,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>0d</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code 0d} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      *
      * @param original the array from which a range is to be copied
      * @param from the initial index of the range to be copied, inclusive
@@ -3650,8 +4160,8 @@
      *     truncated or padded with zeros to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static double[] copyOfRange(double[] original, int from, int to) {
@@ -3666,17 +4176,17 @@
 
     /**
      * Copies the specified range of the specified array into a new array.
-     * The initial index of the range (<tt>from</tt>) must lie between zero
-     * and <tt>original.length</tt>, inclusive.  The value at
-     * <tt>original[from]</tt> is placed into the initial element of the copy
-     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
      * Values from subsequent elements in the original array are placed into
      * subsequent elements in the copy.  The final index of the range
-     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
-     * may be greater than <tt>original.length</tt>, in which case
-     * <tt>false</tt> is placed in all elements of the copy whose index is
-     * greater than or equal to <tt>original.length - from</tt>.  The length
-     * of the returned array will be <tt>to - from</tt>.
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code false} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
      *
      * @param original the array from which a range is to be copied
      * @param from the initial index of the range to be copied, inclusive
@@ -3686,8 +4196,8 @@
      *     truncated or padded with false elements to obtain the required length
      * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
      *     or {@code from > original.length}
-     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
-     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
      * @since 1.6
      */
     public static boolean[] copyOfRange(boolean[] original, int from, int to) {
@@ -3745,7 +4255,7 @@
 
         @Override
         public Object[] toArray() {
-            return a.clone();
+            return Arrays.copyOf(a, a.length, Object[].class);
         }
 
         @Override
@@ -3790,7 +4300,7 @@
 
         @Override
         public boolean contains(Object o) {
-            return indexOf(o) != -1;
+            return indexOf(o) >= 0;
         }
 
         @Override
@@ -3819,22 +4329,51 @@
         public void sort(Comparator<? super E> c) {
             Arrays.sort(a, c);
         }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new ArrayItr<>(a);
+        }
+    }
+
+    private static class ArrayItr<E> implements Iterator<E> {
+        private int cursor;
+        private final E[] a;
+
+        ArrayItr(E[] a) {
+            this.a = a;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return cursor < a.length;
+        }
+
+        @Override
+        public E next() {
+            int i = cursor;
+            if (i >= a.length) {
+                throw new NoSuchElementException();
+            }
+            cursor = i + 1;
+            return a[i];
+        }
     }
 
     /**
      * Returns a hash code based on the contents of the specified array.
-     * For any two <tt>long</tt> arrays <tt>a</tt> and <tt>b</tt>
-     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * For any two {@code long} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is the same value that would be
-     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * obtained by invoking the {@link List#hashCode() hashCode}
      * method on a {@link List} containing a sequence of {@link Long}
-     * instances representing the elements of <tt>a</tt> in the same order.
-     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
      *
      * @param a the array whose hash value to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @since 1.5
      */
     public static int hashCode(long a[]) {
@@ -3852,18 +4391,18 @@
 
     /**
      * Returns a hash code based on the contents of the specified array.
-     * For any two non-null <tt>int</tt> arrays <tt>a</tt> and <tt>b</tt>
-     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * For any two non-null {@code int} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is the same value that would be
-     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * obtained by invoking the {@link List#hashCode() hashCode}
      * method on a {@link List} containing a sequence of {@link Integer}
-     * instances representing the elements of <tt>a</tt> in the same order.
-     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
      *
      * @param a the array whose hash value to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @since 1.5
      */
     public static int hashCode(int a[]) {
@@ -3879,18 +4418,18 @@
 
     /**
      * Returns a hash code based on the contents of the specified array.
-     * For any two <tt>short</tt> arrays <tt>a</tt> and <tt>b</tt>
-     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * For any two {@code short} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is the same value that would be
-     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * obtained by invoking the {@link List#hashCode() hashCode}
      * method on a {@link List} containing a sequence of {@link Short}
-     * instances representing the elements of <tt>a</tt> in the same order.
-     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
      *
      * @param a the array whose hash value to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @since 1.5
      */
     public static int hashCode(short a[]) {
@@ -3906,18 +4445,18 @@
 
     /**
      * Returns a hash code based on the contents of the specified array.
-     * For any two <tt>char</tt> arrays <tt>a</tt> and <tt>b</tt>
-     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * For any two {@code char} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is the same value that would be
-     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * obtained by invoking the {@link List#hashCode() hashCode}
      * method on a {@link List} containing a sequence of {@link Character}
-     * instances representing the elements of <tt>a</tt> in the same order.
-     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
      *
      * @param a the array whose hash value to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @since 1.5
      */
     public static int hashCode(char a[]) {
@@ -3933,18 +4472,18 @@
 
     /**
      * Returns a hash code based on the contents of the specified array.
-     * For any two <tt>byte</tt> arrays <tt>a</tt> and <tt>b</tt>
-     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * For any two {@code byte} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is the same value that would be
-     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * obtained by invoking the {@link List#hashCode() hashCode}
      * method on a {@link List} containing a sequence of {@link Byte}
-     * instances representing the elements of <tt>a</tt> in the same order.
-     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
      *
      * @param a the array whose hash value to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @since 1.5
      */
     public static int hashCode(byte a[]) {
@@ -3960,18 +4499,18 @@
 
     /**
      * Returns a hash code based on the contents of the specified array.
-     * For any two <tt>boolean</tt> arrays <tt>a</tt> and <tt>b</tt>
-     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * For any two {@code boolean} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is the same value that would be
-     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * obtained by invoking the {@link List#hashCode() hashCode}
      * method on a {@link List} containing a sequence of {@link Boolean}
-     * instances representing the elements of <tt>a</tt> in the same order.
-     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
      *
      * @param a the array whose hash value to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @since 1.5
      */
     public static int hashCode(boolean a[]) {
@@ -3987,18 +4526,18 @@
 
     /**
      * Returns a hash code based on the contents of the specified array.
-     * For any two <tt>float</tt> arrays <tt>a</tt> and <tt>b</tt>
-     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * For any two {@code float} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is the same value that would be
-     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * obtained by invoking the {@link List#hashCode() hashCode}
      * method on a {@link List} containing a sequence of {@link Float}
-     * instances representing the elements of <tt>a</tt> in the same order.
-     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
      *
      * @param a the array whose hash value to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @since 1.5
      */
     public static int hashCode(float a[]) {
@@ -4014,18 +4553,18 @@
 
     /**
      * Returns a hash code based on the contents of the specified array.
-     * For any two <tt>double</tt> arrays <tt>a</tt> and <tt>b</tt>
-     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * For any two {@code double} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is the same value that would be
-     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * obtained by invoking the {@link List#hashCode() hashCode}
      * method on a {@link List} containing a sequence of {@link Double}
-     * instances representing the elements of <tt>a</tt> in the same order.
-     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
      *
      * @param a the array whose hash value to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @since 1.5
      */
     public static int hashCode(double a[]) {
@@ -4048,16 +4587,16 @@
      * element,  either directly or indirectly through one or more levels of
      * arrays.
      *
-     * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
-     * <tt>Arrays.equals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     * <p>For any two arrays {@code a} and {@code b} such that
+     * {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
      *
      * <p>The value returned by this method is equal to the value that would
-     * be returned by <tt>Arrays.asList(a).hashCode()</tt>, unless <tt>a</tt>
-     * is <tt>null</tt>, in which case <tt>0</tt> is returned.
+     * be returned by {@code Arrays.asList(a).hashCode()}, unless {@code a}
+     * is {@code null}, in which case {@code 0} is returned.
      *
      * @param a the array whose content-based hash code to compute
-     * @return a content-based hash code for <tt>a</tt>
+     * @return a content-based hash code for {@code a}
      * @see #deepHashCode(Object[])
      * @since 1.5
      */
@@ -4082,23 +4621,23 @@
      * one or more levels of arrays.  The behavior of such an invocation is
      * undefined.
      *
-     * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
-     * <tt>Arrays.deepEquals(a, b)</tt>, it is also the case that
-     * <tt>Arrays.deepHashCode(a) == Arrays.deepHashCode(b)</tt>.
+     * <p>For any two arrays {@code a} and {@code b} such that
+     * {@code Arrays.deepEquals(a, b)}, it is also the case that
+     * {@code Arrays.deepHashCode(a) == Arrays.deepHashCode(b)}.
      *
      * <p>The computation of the value returned by this method is similar to
      * that of the value returned by {@link List#hashCode()} on a list
-     * containing the same elements as <tt>a</tt> in the same order, with one
-     * difference: If an element <tt>e</tt> of <tt>a</tt> is itself an array,
-     * its hash code is computed not by calling <tt>e.hashCode()</tt>, but as
-     * by calling the appropriate overloading of <tt>Arrays.hashCode(e)</tt>
-     * if <tt>e</tt> is an array of a primitive type, or as by calling
-     * <tt>Arrays.deepHashCode(e)</tt> recursively if <tt>e</tt> is an array
-     * of a reference type.  If <tt>a</tt> is <tt>null</tt>, this method
+     * containing the same elements as {@code a} in the same order, with one
+     * difference: If an element {@code e} of {@code a} is itself an array,
+     * its hash code is computed not by calling {@code e.hashCode()}, but as
+     * by calling the appropriate overloading of {@code Arrays.hashCode(e)}
+     * if {@code e} is an array of a primitive type, or as by calling
+     * {@code Arrays.deepHashCode(e)} recursively if {@code e} is an array
+     * of a reference type.  If {@code a} is {@code null}, this method
      * returns 0.
      *
      * @param a the array whose deep-content-based hash code to compute
-     * @return a deep-content-based hash code for <tt>a</tt>
+     * @return a deep-content-based hash code for {@code a}
      * @see #hashCode(Object[])
      * @since 1.5
      */
@@ -4109,63 +4648,60 @@
         int result = 1;
 
         for (Object element : a) {
-            int elementHash = 0;
-            // BEGIN Android-changed: getComponentType() is faster than instanceof().
-            if (element != null) {
-                Class<?> cl = element.getClass().getComponentType();
-                if (cl == null)
-                    elementHash = element.hashCode();
-                else if (element instanceof Object[])
-                    elementHash = deepHashCode((Object[]) element);
-                else if (cl == byte.class)
-                    elementHash = hashCode((byte[]) element);
-                else if (cl == short.class)
-                    elementHash = hashCode((short[]) element);
-                else if (cl == int.class)
-                    elementHash = hashCode((int[]) element);
-                else if (cl == long.class)
-                    elementHash = hashCode((long[]) element);
-                else if (cl == char.class)
-                    elementHash = hashCode((char[]) element);
-                else if (cl == float.class)
-                    elementHash = hashCode((float[]) element);
-                else if (cl == double.class)
-                    elementHash = hashCode((double[]) element);
-                else if (cl == boolean.class)
-                    elementHash = hashCode((boolean[]) element);
-                else
-                    elementHash = element.hashCode();
-            }
-            // END Android-changed: getComponentType() is faster than instanceof().
+            final int elementHash;
+            final Class<?> cl;
+            if (element == null)
+                elementHash = 0;
+            else if ((cl = element.getClass().getComponentType()) == null)
+                elementHash = element.hashCode();
+            else if (element instanceof Object[])
+                elementHash = deepHashCode((Object[]) element);
+            else
+                elementHash = primitiveArrayHashCode(element, cl);
+
             result = 31 * result + elementHash;
         }
 
         return result;
     }
 
+    private static int primitiveArrayHashCode(Object a, Class<?> cl) {
+        return
+            (cl == byte.class)    ? hashCode((byte[]) a)    :
+            (cl == int.class)     ? hashCode((int[]) a)     :
+            (cl == long.class)    ? hashCode((long[]) a)    :
+            (cl == char.class)    ? hashCode((char[]) a)    :
+            (cl == short.class)   ? hashCode((short[]) a)   :
+            (cl == boolean.class) ? hashCode((boolean[]) a) :
+            (cl == double.class)  ? hashCode((double[]) a)  :
+            // If new primitive types are ever added, this method must be
+            // expanded or we will fail here with ClassCastException.
+            hashCode((float[]) a);
+    }
+
     /**
-     * Returns <tt>true</tt> if the two specified arrays are <i>deeply
+     * Returns {@code true} if the two specified arrays are <i>deeply
      * equal</i> to one another.  Unlike the {@link #equals(Object[],Object[])}
      * method, this method is appropriate for use with nested arrays of
      * arbitrary depth.
      *
      * <p>Two array references are considered deeply equal if both
-     * are <tt>null</tt>, or if they refer to arrays that contain the same
+     * are {@code null}, or if they refer to arrays that contain the same
      * number of elements and all corresponding pairs of elements in the two
      * arrays are deeply equal.
      *
-     * <p>Two possibly <tt>null</tt> elements <tt>e1</tt> and <tt>e2</tt> are
+     * <p>Two possibly {@code null} elements {@code e1} and {@code e2} are
      * deeply equal if any of the following conditions hold:
      * <ul>
-     *    <li> <tt>e1</tt> and <tt>e2</tt> are both arrays of object reference
-     *         types, and <tt>Arrays.deepEquals(e1, e2) would return true</tt>
-     *    <li> <tt>e1</tt> and <tt>e2</tt> are arrays of the same primitive
+     *    <li> {@code e1} and {@code e2} are both arrays of object reference
+     *         types, and {@code Arrays.deepEquals(e1, e2) would return true}
+     *    <li> {@code e1} and {@code e2} are arrays of the same primitive
      *         type, and the appropriate overloading of
-     *         <tt>Arrays.equals(e1, e2)</tt> would return true.
-     *    <li> <tt>e1 == e2</tt>
-     *    <li> <tt>e1.equals(e2)</tt> would return true.
+     *         {@code Arrays.equals(e1, e2)} would return true.
+     *    <li> {@code e1 == e2}
+     *    <li> {@code e1.equals(e2)} would return true.
      * </ul>
-     * Note that this definition permits <tt>null</tt> elements at any depth.
+     * Note that this definition permits {@code null} elements at any depth.
      *
      * <p>If either of the specified arrays contain themselves as elements
      * either directly or indirectly through one or more levels of arrays,
@@ -4173,7 +4709,7 @@
      *
      * @param a1 one array to be tested for equality
      * @param a2 the other array to be tested for equality
-     * @return <tt>true</tt> if the two arrays are equal
+     * @return {@code true} if the two arrays are equal
      * @see #equals(Object[],Object[])
      * @see Objects#deepEquals(Object, Object)
      * @since 1.5
@@ -4234,14 +4770,14 @@
     /**
      * Returns a string representation of the contents of the specified array.
      * The string representation consists of a list of the array's elements,
-     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
-     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
      * space).  Elements are converted to strings as by
-     * <tt>String.valueOf(long)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
-     * is <tt>null</tt>.
+     * {@code String.valueOf(long)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @since 1.5
      */
     public static String toString(long[] a) {
@@ -4264,14 +4800,14 @@
     /**
      * Returns a string representation of the contents of the specified array.
      * The string representation consists of a list of the array's elements,
-     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
-     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
      * space).  Elements are converted to strings as by
-     * <tt>String.valueOf(int)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt> is
-     * <tt>null</tt>.
+     * {@code String.valueOf(int)}.  Returns {@code "null"} if {@code a} is
+     * {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @since 1.5
      */
     public static String toString(int[] a) {
@@ -4294,14 +4830,14 @@
     /**
      * Returns a string representation of the contents of the specified array.
      * The string representation consists of a list of the array's elements,
-     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
-     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
      * space).  Elements are converted to strings as by
-     * <tt>String.valueOf(short)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
-     * is <tt>null</tt>.
+     * {@code String.valueOf(short)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @since 1.5
      */
     public static String toString(short[] a) {
@@ -4324,14 +4860,14 @@
     /**
      * Returns a string representation of the contents of the specified array.
      * The string representation consists of a list of the array's elements,
-     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
-     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
      * space).  Elements are converted to strings as by
-     * <tt>String.valueOf(char)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
-     * is <tt>null</tt>.
+     * {@code String.valueOf(char)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @since 1.5
      */
     public static String toString(char[] a) {
@@ -4354,14 +4890,14 @@
     /**
      * Returns a string representation of the contents of the specified array.
      * The string representation consists of a list of the array's elements,
-     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements
-     * are separated by the characters <tt>", "</tt> (a comma followed
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements
+     * are separated by the characters {@code ", "} (a comma followed
      * by a space).  Elements are converted to strings as by
-     * <tt>String.valueOf(byte)</tt>.  Returns <tt>"null"</tt> if
-     * <tt>a</tt> is <tt>null</tt>.
+     * {@code String.valueOf(byte)}.  Returns {@code "null"} if
+     * {@code a} is {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @since 1.5
      */
     public static String toString(byte[] a) {
@@ -4384,14 +4920,14 @@
     /**
      * Returns a string representation of the contents of the specified array.
      * The string representation consists of a list of the array's elements,
-     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
-     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
      * space).  Elements are converted to strings as by
-     * <tt>String.valueOf(boolean)</tt>.  Returns <tt>"null"</tt> if
-     * <tt>a</tt> is <tt>null</tt>.
+     * {@code String.valueOf(boolean)}.  Returns {@code "null"} if
+     * {@code a} is {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @since 1.5
      */
     public static String toString(boolean[] a) {
@@ -4414,14 +4950,14 @@
     /**
      * Returns a string representation of the contents of the specified array.
      * The string representation consists of a list of the array's elements,
-     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
-     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
      * space).  Elements are converted to strings as by
-     * <tt>String.valueOf(float)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
-     * is <tt>null</tt>.
+     * {@code String.valueOf(float)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @since 1.5
      */
     public static String toString(float[] a) {
@@ -4445,14 +4981,14 @@
     /**
      * Returns a string representation of the contents of the specified array.
      * The string representation consists of a list of the array's elements,
-     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
-     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
      * space).  Elements are converted to strings as by
-     * <tt>String.valueOf(double)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
-     * is <tt>null</tt>.
+     * {@code String.valueOf(double)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @since 1.5
      */
     public static String toString(double[] a) {
@@ -4476,15 +5012,15 @@
      * Returns a string representation of the contents of the specified array.
      * If the array contains other arrays as elements, they are converted to
      * strings by the {@link Object#toString} method inherited from
-     * <tt>Object</tt>, which describes their <i>identities</i> rather than
+     * {@code Object}, which describes their <i>identities</i> rather than
      * their contents.
      *
      * <p>The value returned by this method is equal to the value that would
-     * be returned by <tt>Arrays.asList(a).toString()</tt>, unless <tt>a</tt>
-     * is <tt>null</tt>, in which case <tt>"null"</tt> is returned.
+     * be returned by {@code Arrays.asList(a).toString()}, unless {@code a}
+     * is {@code null}, in which case {@code "null"} is returned.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @see #deepToString(Object[])
      * @since 1.5
      */
@@ -4513,29 +5049,29 @@
      * designed for converting multidimensional arrays to strings.
      *
      * <p>The string representation consists of a list of the array's
-     * elements, enclosed in square brackets (<tt>"[]"</tt>).  Adjacent
-     * elements are separated by the characters <tt>", "</tt> (a comma
+     * elements, enclosed in square brackets ({@code "[]"}).  Adjacent
+     * elements are separated by the characters {@code ", "} (a comma
      * followed by a space).  Elements are converted to strings as by
-     * <tt>String.valueOf(Object)</tt>, unless they are themselves
+     * {@code String.valueOf(Object)}, unless they are themselves
      * arrays.
      *
-     * <p>If an element <tt>e</tt> is an array of a primitive type, it is
+     * <p>If an element {@code e} is an array of a primitive type, it is
      * converted to a string as by invoking the appropriate overloading of
-     * <tt>Arrays.toString(e)</tt>.  If an element <tt>e</tt> is an array of a
+     * {@code Arrays.toString(e)}.  If an element {@code e} is an array of a
      * reference type, it is converted to a string as by invoking
      * this method recursively.
      *
      * <p>To avoid infinite recursion, if the specified array contains itself
      * as an element, or contains an indirect reference to itself through one
      * or more levels of arrays, the self-reference is converted to the string
-     * <tt>"[...]"</tt>.  For example, an array containing only a reference
-     * to itself would be rendered as <tt>"[[...]]"</tt>.
+     * {@code "[...]"}.  For example, an array containing only a reference
+     * to itself would be rendered as {@code "[[...]]"}.
      *
-     * <p>This method returns <tt>"null"</tt> if the specified array
-     * is <tt>null</tt>.
+     * <p>This method returns {@code "null"} if the specified array
+     * is {@code null}.
      *
      * @param a the array whose string representation to return
-     * @return a string representation of <tt>a</tt>
+     * @return a string representation of {@code a}
      * @see #toString(Object[])
      * @since 1.5
      */
@@ -4547,7 +5083,7 @@
         if (a.length != 0 && bufLen <= 0)
             bufLen = Integer.MAX_VALUE;
         StringBuilder buf = new StringBuilder(bufLen);
-        deepToString(a, buf, new HashSet<Object[]>());
+        deepToString(a, buf, new HashSet<>());
         return buf.toString();
     }
 
@@ -4616,6 +5152,14 @@
      * <p>If the generator function throws an exception, it is relayed to
      * the caller and the array is left in an indeterminate state.
      *
+     * @apiNote
+     * Setting a subrange of an array, using a generator function to compute
+     * each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.apply(i));
+     * }</pre>
+     *
      * @param <T> type of elements of the array
      * @param array array to be initialized
      * @param generator a function accepting an index and producing the desired
@@ -4637,6 +5181,15 @@
      * is thrown from {@code parallelSetAll} and the array is left in an
      * indeterminate state.
      *
+     * @apiNote
+     * Setting a subrange of an array, in parallel, using a generator function
+     * to compute each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.apply(i));
+     * }</pre>
+     *
      * @param <T> type of elements of the array
      * @param array array to be initialized
      * @param generator a function accepting an index and producing the desired
@@ -4656,6 +5209,14 @@
      * <p>If the generator function throws an exception, it is relayed to
      * the caller and the array is left in an indeterminate state.
      *
+     * @apiNote
+     * Setting a subrange of an array, using a generator function to compute
+     * each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsInt(i));
+     * }</pre>
+     *
      * @param array array to be initialized
      * @param generator a function accepting an index and producing the desired
      *        value for that position
@@ -4676,6 +5237,15 @@
      * is thrown from {@code parallelSetAll} and the array is left in an
      * indeterminate state.
      *
+     * @apiNote
+     * Setting a subrange of an array, in parallel, using a generator function
+     * to compute each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsInt(i));
+     * }</pre>
+     *
      * @param array array to be initialized
      * @param generator a function accepting an index and producing the desired
      * value for that position
@@ -4694,6 +5264,14 @@
      * <p>If the generator function throws an exception, it is relayed to
      * the caller and the array is left in an indeterminate state.
      *
+     * @apiNote
+     * Setting a subrange of an array, using a generator function to compute
+     * each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsLong(i));
+     * }</pre>
+     *
      * @param array array to be initialized
      * @param generator a function accepting an index and producing the desired
      *        value for that position
@@ -4714,6 +5292,15 @@
      * is thrown from {@code parallelSetAll} and the array is left in an
      * indeterminate state.
      *
+     * @apiNote
+     * Setting a subrange of an array, in parallel, using a generator function
+     * to compute each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsLong(i));
+     * }</pre>
+     *
      * @param array array to be initialized
      * @param generator a function accepting an index and producing the desired
      *        value for that position
@@ -4732,6 +5319,14 @@
      * <p>If the generator function throws an exception, it is relayed to
      * the caller and the array is left in an indeterminate state.
      *
+     * @apiNote
+     * Setting a subrange of an array, using a generator function to compute
+     * each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
+     * }</pre>
+     *
      * @param array array to be initialized
      * @param generator a function accepting an index and producing the desired
      *        value for that position
@@ -4752,6 +5347,15 @@
      * is thrown from {@code parallelSetAll} and the array is left in an
      * indeterminate state.
      *
+     * @apiNote
+     * Setting a subrange of an array, in parallel, using a generator function
+     * to compute each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
+     * }</pre>
+     *
      * @param array array to be initialized
      * @param generator a function accepting an index and producing the desired
      *        value for that position
@@ -5043,4 +5647,3185 @@
     public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
         return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false);
     }
+
+
+    // Comparison methods
+
+    // Compare boolean
+
+    /**
+     * Compares two {@code boolean} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Boolean#compare(boolean, boolean)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(boolean[], boolean[])} for the definition of a
+     * common and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(boolean[], boolean[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Boolean.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(boolean[] a, boolean[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Boolean.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code boolean} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Boolean#compare(boolean, boolean)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(boolean[], int, int, boolean[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(boolean[], int, int, boolean[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(boolean[] a, int aFromIndex, int aToIndex,
+                              boolean[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare byte
+
+    /**
+     * Compares two {@code byte} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Byte#compare(byte, byte)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(byte[], byte[])} for the definition of a common and
+     * proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(byte[], byte[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Byte.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(byte[] a, byte[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Byte.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code byte} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Byte#compare(byte, byte)}, at a relative index
+     * within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(byte[], int, int, byte[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(byte[] a, int aFromIndex, int aToIndex,
+                              byte[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code byte} arrays lexicographically, numerically treating
+     * elements as unsigned.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Byte#compareUnsigned(byte, byte)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(byte[], byte[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Byte.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are
+     *         equal and contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compareUnsigned(byte[] a, byte[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Byte.compareUnsigned(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+
+    /**
+     * Compares two {@code byte} arrays lexicographically over the specified
+     * ranges, numerically treating elements as unsigned.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Byte#compareUnsigned(byte, byte)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is null
+     * @since 9
+     */
+    public static int compareUnsigned(byte[] a, int aFromIndex, int aToIndex,
+                                      byte[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare short
+
+    /**
+     * Compares two {@code short} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Short#compare(short, short)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(short[], short[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(short[], short[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Short.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(short[] a, short[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Short.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code short} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Short#compare(short, short)}, at a relative
+     * index within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(short[], int, int, short[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(short[], int, int, short[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Short.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(short[] a, int aFromIndex, int aToIndex,
+                              short[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Short.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code short} arrays lexicographically, numerically treating
+     * elements as unsigned.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Short#compareUnsigned(short, short)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(short[], short[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Short.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are
+     *         equal and contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compareUnsigned(short[] a, short[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Short.compareUnsigned(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code short} arrays lexicographically over the specified
+     * ranges, numerically treating elements as unsigned.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Short#compareUnsigned(short, short)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(short[], int, int, short[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is null
+     * @since 9
+     */
+    public static int compareUnsigned(short[] a, int aFromIndex, int aToIndex,
+                                      short[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare char
+
+    /**
+     * Compares two {@code char} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Character#compare(char, char)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(char[], char[])} for the definition of a common and
+     * proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(char[], char[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Character.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(char[] a, char[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Character.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code char} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Character#compare(char, char)}, at a relative
+     * index within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(char[], int, int, char[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(char[], int, int, char[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Character.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(char[] a, int aFromIndex, int aToIndex,
+                              char[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Character.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare int
+
+    /**
+     * Compares two {@code int} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Integer#compare(int, int)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(int[], int[])} for the definition of a common and
+     * proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(int[], int[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Integer.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(int[] a, int[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Integer.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code int} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Integer#compare(int, int)}, at a relative index
+     * within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(int[], int, int, int[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(int[], int, int, int[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(int[] a, int aFromIndex, int aToIndex,
+                              int[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code int} arrays lexicographically, numerically treating
+     * elements as unsigned.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Integer#compareUnsigned(int, int)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(int[], int[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Integer.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are
+     *         equal and contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compareUnsigned(int[] a, int[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Integer.compareUnsigned(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code int} arrays lexicographically over the specified
+     * ranges, numerically treating elements as unsigned.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Integer#compareUnsigned(int, int)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(int[], int, int, int[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is null
+     * @since 9
+     */
+    public static int compareUnsigned(int[] a, int aFromIndex, int aToIndex,
+                                      int[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare long
+
+    /**
+     * Compares two {@code long} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Long#compare(long, long)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(long[], long[])} for the definition of a common and
+     * proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(long[], long[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Long.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(long[] a, long[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Long.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code long} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Long#compare(long, long)}, at a relative index
+     * within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(long[], int, int, long[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(long[], int, int, long[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Long.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(long[] a, int aFromIndex, int aToIndex,
+                              long[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Long.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code long} arrays lexicographically, numerically treating
+     * elements as unsigned.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Long#compareUnsigned(long, long)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(long[], long[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Long.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are
+     *         equal and contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compareUnsigned(long[] a, long[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Long.compareUnsigned(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code long} arrays lexicographically over the specified
+     * ranges, numerically treating elements as unsigned.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Long#compareUnsigned(long, long)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(long[], int, int, long[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is null
+     * @since 9
+     */
+    public static int compareUnsigned(long[] a, int aFromIndex, int aToIndex,
+                                      long[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare float
+
+    /**
+     * Compares two {@code float} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Float#compare(float, float)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(float[], float[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(float[], float[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Float.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(float[] a, float[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Float.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code float} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Float#compare(float, float)}, at a relative
+     * index within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(float[], int, int, float[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(float[], int, int, float[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Float.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(float[] a, int aFromIndex, int aToIndex,
+                              float[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Float.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare double
+
+    /**
+     * Compares two {@code double} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Double#compare(double, double)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(double[], double[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(double[], double[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Double.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(double[] a, double[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Double.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code double} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Double#compare(double, double)}, at a relative
+     * index within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(double[], int, int, double[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(double[], int, int, double[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Double.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(double[] a, int aFromIndex, int aToIndex,
+                              double[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Double.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare objects
+
+    /**
+     * Compares two {@code Object} arrays, within comparable elements,
+     * lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements of type {@code T} at
+     * an index {@code i} within the respective arrays that is the prefix
+     * length, as if by:
+     * <pre>{@code
+     *     Comparator.nullsFirst(Comparator.<T>naturalOrder()).
+     *         compare(a[i], b[i])
+     * }</pre>
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(Object[], Object[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     * A {@code null} array element is considered lexicographically than a
+     * non-{@code null} array element.  Two {@code null} array elements are
+     * considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(Object[], Object[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references
+     * and elements):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return a[i].compareTo(b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @param <T> the type of comparable array elements
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static <T extends Comparable<? super T>> int compare(T[] a, T[] b) {
+        if (a == b)
+            return 0;
+        // A null array is less than a non-null array
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int length = Math.min(a.length, b.length);
+        for (int i = 0; i < length; i++) {
+            T oa = a[i];
+            T ob = b[i];
+            if (oa != ob) {
+                // A null element is less than a non-null element
+                if (oa == null || ob == null)
+                    return oa == null ? -1 : 1;
+                int v = oa.compareTo(ob);
+                if (v != 0) {
+                    return v;
+                }
+            }
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code Object} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements of type {@code T} at a relative index {@code i} within the
+     * respective arrays that is the prefix length, as if by:
+     * <pre>{@code
+     *     Comparator.nullsFirst(Comparator.<T>naturalOrder()).
+     *         compare(a[aFromIndex + i, b[bFromIndex + i])
+     * }</pre>
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(Object[], int, int, Object[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array elements):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return a[aFromIndex + i].compareTo(b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @param <T> the type of comparable array elements
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static <T extends Comparable<? super T>> int compare(
+            T[] a, int aFromIndex, int aToIndex,
+            T[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        for (int i = 0; i < length; i++) {
+            T oa = a[aFromIndex++];
+            T ob = b[bFromIndex++];
+            if (oa != ob) {
+                if (oa == null || ob == null)
+                    return oa == null ? -1 : 1;
+                int v = oa.compareTo(ob);
+                if (v != 0) {
+                    return v;
+                }
+            }
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code Object} arrays lexicographically using a specified
+     * comparator.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing with the specified comparator two
+     * elements at an index within the respective arrays that is the prefix
+     * length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(Object[], Object[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b, cmp);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return cmp.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @throws NullPointerException if the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> int compare(T[] a, T[] b,
+                                  Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int length = Math.min(a.length, b.length);
+        for (int i = 0; i < length; i++) {
+            T oa = a[i];
+            T ob = b[i];
+            if (oa != ob) {
+                // Null-value comparison is deferred to the comparator
+                int v = cmp.compare(oa, ob);
+                if (v != 0) {
+                    return v;
+                }
+            }
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code Object} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing with the
+     * specified comparator two elements at a relative index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array elements):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex, cmp);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return cmp.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array or the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> int compare(
+            T[] a, int aFromIndex, int aToIndex,
+            T[] b, int bFromIndex, int bToIndex,
+            Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        for (int i = 0; i < length; i++) {
+            T oa = a[aFromIndex++];
+            T ob = b[bFromIndex++];
+            if (oa != ob) {
+                // Null-value comparison is deferred to the comparator
+                int v = cmp.compare(oa, ob);
+                if (v != 0) {
+                    return v;
+                }
+            }
+        }
+
+        return aLength - bLength;
+    }
+
+
+    // Mismatch methods
+
+    // Mismatch boolean
+
+    /**
+     * Finds and returns the index of the first mismatch between two
+     * {@code boolean} arrays, otherwise return -1 if no mismatch is found.  The
+     * index will be in the range of 0 (inclusive) up to the length (inclusive)
+     * of the smaller array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(boolean[] a, boolean[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code boolean} arrays over the specified ranges, otherwise return -1 if
+     * no mismatch is found.  The index will be in the range of 0 (inclusive) up
+     * to the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(boolean[] a, int aFromIndex, int aToIndex,
+                               boolean[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch byte
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code byte}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(byte[] a, byte[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code byte} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(byte[] a, int aFromIndex, int aToIndex,
+                               byte[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch char
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code char}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(char[] a, char[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code char} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(char[] a, int aFromIndex, int aToIndex,
+                               char[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch short
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code short}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(short[] a, short[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code short} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(short[] a, int aFromIndex, int aToIndex,
+                               short[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch int
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code int}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(int[] a, int[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code int} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(int[] a, int aFromIndex, int aToIndex,
+                               int[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch long
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code long}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(long[] a, long[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code long} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(long[] a, int aFromIndex, int aToIndex,
+                               long[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch float
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code float}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     Float.compare(a[pl], b[pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(float[] a, float[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code float} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     Float.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(float[] a, int aFromIndex, int aToIndex,
+                               float[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch double
+
+    /**
+     * Finds and returns the index of the first mismatch between two
+     * {@code double} arrays, otherwise return -1 if no mismatch is found.  The
+     * index will be in the range of 0 (inclusive) up to the length (inclusive)
+     * of the smaller array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     Double.compare(a[pl], b[pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(double[] a, double[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code double} arrays over the specified ranges, otherwise return -1 if
+     * no mismatch is found.  The index will be in the range of 0 (inclusive) up
+     * to the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     Double.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(double[] a, int aFromIndex, int aToIndex,
+                               double[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch objects
+
+    /**
+     * Finds and returns the index of the first mismatch between two
+     * {@code Object} arrays, otherwise return -1 if no mismatch is found.  The
+     * index will be in the range of 0 (inclusive) up to the length (inclusive)
+     * of the smaller array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     !Objects.equals(a[pl], b[pl])
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(Object[] a, Object[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        for (int i = 0; i < length; i++) {
+            if (!Objects.equals(a[i], b[i]))
+                return i;
+        }
+
+        return a.length != b.length ? length : -1;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code Object} arrays over the specified ranges, otherwise return -1 if
+     * no mismatch is found.  The index will be in the range of 0 (inclusive) up
+     * to the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     !Objects.equals(a[aFromIndex + pl], b[bFromIndex + pl])
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(
+            Object[] a, int aFromIndex, int aToIndex,
+            Object[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        for (int i = 0; i < length; i++) {
+            if (!Objects.equals(a[aFromIndex++], b[bFromIndex++]))
+                return i;
+        }
+
+        return aLength != bLength ? length : -1;
+    }
+
+    /**
+     * Finds and returns the index of the first mismatch between two
+     * {@code Object} arrays, otherwise return -1 if no mismatch is found.
+     * The index will be in the range of 0 (inclusive) up to the length
+     * (inclusive) of the smaller array.
+     *
+     * <p>The specified comparator is used to determine if two array elements
+     * from the each array are not equal.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl, cmp)
+     *     cmp.compare(a[pl], b[pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length),
+     *                   cmp)
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array or the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> int mismatch(T[] a, T[] b, Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        for (int i = 0; i < length; i++) {
+            T oa = a[i];
+            T ob = b[i];
+            if (oa != ob) {
+                // Null-value comparison is deferred to the comparator
+                int v = cmp.compare(oa, ob);
+                if (v != 0) {
+                    return i;
+                }
+            }
+        }
+
+        return a.length != b.length ? length : -1;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code Object} arrays over the specified ranges, otherwise return -1 if
+     * no mismatch is found.  The index will be in the range of 0 (inclusive) up
+     * to the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl, cmp) &&
+     *     cmp.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   cmp)
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array or the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> int mismatch(
+            T[] a, int aFromIndex, int aToIndex,
+            T[] b, int bFromIndex, int bToIndex,
+            Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        for (int i = 0; i < length; i++) {
+            T oa = a[aFromIndex++];
+            T ob = b[bFromIndex++];
+            if (oa != ob) {
+                // Null-value comparison is deferred to the comparator
+                int v = cmp.compare(oa, ob);
+                if (v != 0) {
+                    return i;
+                }
+            }
+        }
+
+        return aLength != bLength ? length : -1;
+    }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java b/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
index e4d2235..a206867 100644
--- a/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
+++ b/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
@@ -245,8 +245,7 @@
                 Future<T> f = futures.get(i);
                 if (!f.isDone()) {
                     try { f.get(); }
-                    catch (CancellationException ignore) {}
-                    catch (ExecutionException ignore) {}
+                    catch (CancellationException | ExecutionException ignore) {}
                 }
             }
             return futures;
@@ -283,8 +282,7 @@
                 Future<T> f = futures.get(j);
                 if (!f.isDone()) {
                     try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
-                    catch (CancellationException ignore) {}
-                    catch (ExecutionException ignore) {}
+                    catch (CancellationException | ExecutionException ignore) {}
                     catch (TimeoutException timedOut) {
                         break timedOut;
                     }
diff --git a/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
index 96a60b3..dced5a4 100644
--- a/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
@@ -46,10 +46,8 @@
 import java.util.Spliterators;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * A bounded {@linkplain BlockingQueue blocking queue} backed by an
@@ -74,17 +72,24 @@
  * generally decreases throughput but reduces variability and avoids
  * starvation.
  *
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
  *
- * @since 1.5
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
  */
 public class ArrayBlockingQueue<E> extends AbstractQueue<E>
         implements BlockingQueue<E>, java.io.Serializable {
 
+    /*
+     * Much of the implementation mechanics, especially the unusual
+     * nested loops, are shared and co-maintained with ArrayDeque.
+     */
+
     /**
      * Serialization ID. This class relies on default serialization
      * even for the items array, which is default-serialized, even if
@@ -129,10 +134,21 @@
     // Internal helper methods
 
     /**
-     * Circularly decrements array index i.
+     * Increments i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
      */
-    final int dec(int i) {
-        return ((i == 0) ? items.length : i) - 1;
+    static final int inc(int i, int modulus) {
+        if (++i >= modulus) i = 0;
+        return i;
+    }
+
+    /**
+     * Decrements i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int dec(int i, int modulus) {
+        if (--i < 0) i = modulus - 1;
+        return i;
     }
 
     /**
@@ -144,14 +160,24 @@
     }
 
     /**
+     * Returns element at array index i.
+     * This is a slight abuse of generics, accepted by javac.
+     */
+    @SuppressWarnings("unchecked")
+    static <E> E itemAt(Object[] items, int i) {
+        return (E) items[i];
+    }
+
+    /**
      * Inserts element at current put position, advances, and signals.
      * Call only when holding lock.
      */
-    private void enqueue(E x) {
+    private void enqueue(E e) {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[putIndex] == null;
         final Object[] items = this.items;
-        items[putIndex] = x;
+        items[putIndex] = e;
         if (++putIndex == items.length) putIndex = 0;
         count++;
         notEmpty.signal();
@@ -162,18 +188,19 @@
      * Call only when holding lock.
      */
     private E dequeue() {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[takeIndex] != null;
         final Object[] items = this.items;
         @SuppressWarnings("unchecked")
-        E x = (E) items[takeIndex];
+        E e = (E) items[takeIndex];
         items[takeIndex] = null;
         if (++takeIndex == items.length) takeIndex = 0;
         count--;
         if (itrs != null)
             itrs.elementDequeued();
         notFull.signal();
-        return x;
+        return e;
     }
 
     /**
@@ -182,6 +209,7 @@
      * Call only when holding lock.
      */
     void removeAt(final int removeIndex) {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[removeIndex] != null;
         // assert removeIndex >= 0 && removeIndex < items.length;
@@ -267,6 +295,7 @@
         final ReentrantLock lock = this.lock;
         lock.lock(); // Lock only for visibility, not mutual exclusion
         try {
+            final Object[] items = this.items;
             int i = 0;
             try {
                 for (E e : c)
@@ -481,15 +510,16 @@
         try {
             if (count > 0) {
                 final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    if (o.equals(items[i])) {
-                        removeAt(i);
-                        return true;
-                    }
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        if (o.equals(items[i])) {
+                            removeAt(i);
+                            return true;
+                        }
+                    if (to == end) break;
+                }
             }
             return false;
         } finally {
@@ -512,13 +542,14 @@
         try {
             if (count > 0) {
                 final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    if (o.equals(items[i]))
-                        return true;
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        if (o.equals(items[i]))
+                            return true;
+                    if (to == end) break;
+                }
             }
             return false;
         } finally {
@@ -625,15 +656,9 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            int k = count;
-            if (k > 0) {
-                final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    items[i] = null;
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+            int k;
+            if ((k = count) > 0) {
+                circularClear(items, takeIndex, putIndex);
                 takeIndex = putIndex;
                 count = 0;
                 if (itrs != null)
@@ -647,6 +672,20 @@
     }
 
     /**
+     * Nulls out slots starting at array index i, upto index end.
+     * Condition i == end means "full" - the entire array is cleared.
+     */
+    private static void circularClear(Object[] items, int i, int end) {
+        // assert 0 <= i && i < items.length;
+        // assert 0 <= end && end < items.length;
+        for (int to = (i < end) ? end : items.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++) items[i] = null;
+            if (to == end) break;
+        }
+    }
+
+    /**
      * @throws UnsupportedOperationException {@inheritDoc}
      * @throws ClassCastException            {@inheritDoc}
      * @throws NullPointerException          {@inheritDoc}
@@ -678,8 +717,8 @@
             try {
                 while (i < n) {
                     @SuppressWarnings("unchecked")
-                    E x = (E) items[take];
-                    c.add(x);
+                    E e = (E) items[take];
+                    c.add(e);
                     items[take] = null;
                     if (++take == items.length) take = 0;
                     i++;
@@ -808,7 +847,7 @@
          * there is known to be at least one iterator to collect
          */
         void doSomeSweeping(boolean tryHarder) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert head != null;
             int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
             Node o, p;
@@ -864,7 +903,7 @@
          * Adds a new iterator to the linked list of tracked iterators.
          */
         void register(Itr itr) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             head = new Node(itr, head);
         }
 
@@ -874,7 +913,7 @@
          * Notifies all iterators, and expunges any that are now stale.
          */
         void takeIndexWrapped() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             cycles++;
             for (Node o = null, p = head; p != null;) {
                 final Itr it = p.get();
@@ -931,7 +970,7 @@
          * clears all weak refs, and unlinks the itrs datastructure.
          */
         void queueIsEmpty() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             for (Node p = head; p != null; p = p.next) {
                 Itr it = p.get();
                 if (it != null) {
@@ -947,7 +986,7 @@
          * Called whenever an element has been dequeued (at takeIndex).
          */
         void elementDequeued() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (count == 0)
                 queueIsEmpty();
             else if (takeIndex == 0)
@@ -972,6 +1011,11 @@
      * expected element to remove, in lastItem.  Yes, we may fail to
      * remove lastItem from the queue if it moved due to an interleaved
      * interior remove while in detached mode.
+     *
+     * Method forEachRemaining, added in Java 8, is treated similarly
+     * to hasNext returning false, in that we switch to detached mode,
+     * but we regard it as an even stronger request to "close" this
+     * iteration, and don't bother supporting subsequent remove().
      */
     private class Itr implements Iterator<E> {
         /** Index to look for new nextItem; NONE at end */
@@ -1008,7 +1052,6 @@
         private static final int DETACHED = -3;
 
         Itr() {
-            // assert lock.getHoldCount() == 0;
             lastRet = NONE;
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
@@ -1041,12 +1084,12 @@
         }
 
         boolean isDetached() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             return prevTakeIndex < 0;
         }
 
         private int incCursor(int index) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (++index == items.length) index = 0;
             if (index == putIndex) index = NONE;
             return index;
@@ -1071,7 +1114,7 @@
          * operation on this iterator.  Call only from iterating thread.
          */
         private void incorporateDequeues() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert itrs != null;
             // assert !isDetached();
             // assert count > 0;
@@ -1085,7 +1128,7 @@
                 final int len = items.length;
                 // how far takeIndex has advanced since the previous
                 // operation of this iterator
-                long dequeues = (cycles - prevCycles) * len
+                long dequeues = (long) (cycles - prevCycles) * len
                     + (takeIndex - prevTakeIndex);
 
                 // Check indices for invalidation
@@ -1114,7 +1157,7 @@
          */
         private void detach() {
             // Switch to detached mode
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert cursor == NONE;
             // assert nextIndex < 0;
             // assert lastRet < 0 || nextItem == null;
@@ -1134,7 +1177,6 @@
          * triggered by queue modifications.
          */
         public boolean hasNext() {
-            // assert lock.getHoldCount() == 0;
             if (nextItem != null)
                 return true;
             noNext();
@@ -1164,9 +1206,8 @@
         }
 
         public E next() {
-            // assert lock.getHoldCount() == 0;
-            final E x = nextItem;
-            if (x == null)
+            final E e = nextItem;
+            if (e == null)
                 throw new NoSuchElementException();
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
@@ -1184,17 +1225,48 @@
                 } else {
                     nextIndex = NONE;
                     nextItem = null;
+                    if (lastRet == REMOVED) detach();
                 }
             } finally {
                 lock.unlock();
             }
-            return x;
+            return e;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                final E e = nextItem;
+                if (e == null) return;
+                if (!isDetached())
+                    incorporateDequeues();
+                action.accept(e);
+                if (isDetached() || cursor < 0) return;
+                final Object[] items = ArrayBlockingQueue.this.items;
+                for (int i = cursor, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(itemAt(items, i));
+                    if (to == end) break;
+                }
+            } finally {
+                // Calling forEachRemaining is a strong hint that this
+                // iteration is surely over; supporting remove() after
+                // forEachRemaining() is more trouble than it's worth
+                cursor = nextIndex = lastRet = NONE;
+                nextItem = lastItem = null;
+                detach();
+                lock.unlock();
+            }
         }
 
         public void remove() {
-            // assert lock.getHoldCount() == 0;
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
+            // assert lock.getHoldCount() == 1;
             try {
                 if (!isDetached())
                     incorporateDequeues(); // might update lastRet or detach
@@ -1232,7 +1304,7 @@
          * from next(), as promised by returning true from hasNext().
          */
         void shutdown() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             cursor = NONE;
             if (nextIndex >= 0)
                 nextIndex = REMOVED;
@@ -1260,7 +1332,7 @@
          * @return true if this iterator should be unlinked from itrs
          */
         boolean removedAt(int removedIndex) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (isDetached())
                 return true;
 
@@ -1285,7 +1357,7 @@
                 }
                 else if (x > removedDistance) {
                     // assert cursor != prevTakeIndex;
-                    this.cursor = cursor = dec(cursor);
+                    this.cursor = cursor = dec(cursor, len);
                 }
             }
             int lastRet = this.lastRet;
@@ -1294,7 +1366,7 @@
                 if (x == removedDistance)
                     this.lastRet = lastRet = REMOVED;
                 else if (x > removedDistance)
-                    this.lastRet = lastRet = dec(lastRet);
+                    this.lastRet = lastRet = dec(lastRet, len);
             }
             int nextIndex = this.nextIndex;
             if (nextIndex >= 0) {
@@ -1302,7 +1374,7 @@
                 if (x == removedDistance)
                     this.nextIndex = nextIndex = REMOVED;
                 else if (x > removedDistance)
-                    this.nextIndex = nextIndex = dec(nextIndex);
+                    this.nextIndex = nextIndex = dec(nextIndex, len);
             }
             if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
                 this.prevTakeIndex = DETACHED;
@@ -1317,7 +1389,7 @@
          * @return true if this iterator should be unlinked from itrs
          */
         boolean takeIndexWrapped() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (isDetached())
                 return true;
             if (itrs.cycles - prevCycles > 1) {
@@ -1366,4 +1438,197 @@
                     Spliterator.CONCURRENT));
     }
 
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(itemAt(items, i));
+                    if (to == end) break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (itrs == null) { // check for active iterators
+                if (count > 0) {
+                    final Object[] items = this.items;
+                    // Optimize for initial run of survivors
+                    for (int i = takeIndex, end = putIndex,
+                             to = (i < end) ? end : items.length;
+                         ; i = 0, to = end) {
+                        for (; i < to; i++)
+                            if (filter.test(itemAt(items, i)))
+                                return bulkRemoveModified(filter, i);
+                        if (to == end) break;
+                    }
+                }
+                return false;
+            }
+        } finally {
+            lock.unlock();
+        }
+        // Active iterators are too hairy!
+        // Punting (for now) to the slow n^2 algorithm ...
+        return super.removeIf(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /**
+     * Returns circular distance from i to j, disambiguating i == j to
+     * items.length; never returns 0.
+     */
+    private int distanceNonEmpty(int i, int j) {
+        if ((j -= i) <= 0) j += items.length;
+        return j;
+    }
+
+    /**
+     * Helper for bulkRemove, in case of at least one deletion.
+     * Tolerate predicates that reentrantly access the collection for
+     * read (but not write), so traverse once to find elements to
+     * delete, a second pass to physically expunge.
+     *
+     * @param beg valid index of first element to be deleted
+     */
+    private boolean bulkRemoveModified(
+        Predicate<? super E> filter, final int beg) {
+        final Object[] es = items;
+        final int capacity = items.length;
+        final int end = putIndex;
+        final long[] deathRow = nBits(distanceNonEmpty(beg, putIndex));
+        deathRow[0] = 1L;   // set bit 0
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; i = 0, to = end, k -= capacity) {
+            for (; i < to; i++)
+                if (filter.test(itemAt(es, i)))
+                    setBit(deathRow, i - k);
+            if (to == end) break;
+        }
+        // a two-finger traversal, with hare i reading, tortoise w writing
+        int w = beg;
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; w = 0) { // w rejoins i on second leg
+            // In this loop, i and w are on the same leg, with i > w
+            for (; i < to; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (to == end) break;
+            // In this loop, w is on the first leg, i on the second
+            for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (i >= to) {
+                if (w == capacity) w = 0; // "corner" case
+                break;
+            }
+        }
+        count -= distanceNonEmpty(w, end);
+        circularClear(es, putIndex = w, end);
+        return true;
+    }
+
+    /** debugging */
+    void checkInvariants() {
+        // meta-assertions
+        // assert lock.isHeldByCurrentThread();
+        if (!invariantsSatisfied()) {
+            String detail = String.format(
+                "takeIndex=%d putIndex=%d count=%d capacity=%d items=%s",
+                takeIndex, putIndex, count, items.length,
+                Arrays.toString(items));
+            System.err.println(detail);
+            throw new AssertionError(detail);
+        }
+    }
+
+    private boolean invariantsSatisfied() {
+        // Unlike ArrayDeque, we have a count field but no spare slot.
+        // We prefer ArrayDeque's strategy (and the names of its fields!),
+        // but our field layout is baked into the serial form, and so is
+        // too annoying to change.
+        //
+        // putIndex == takeIndex must be disambiguated by checking count.
+        int capacity = items.length;
+        return capacity > 0
+            && items.getClass() == Object[].class
+            && (takeIndex | putIndex | count) >= 0
+            && takeIndex <  capacity
+            && putIndex  <  capacity
+            && count     <= capacity
+            && (putIndex - takeIndex - count) % capacity == 0
+            && (count == 0 || items[takeIndex] != null)
+            && (count == capacity || items[putIndex] == null)
+            && (count == 0 || items[dec(putIndex, capacity)] != null);
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     *
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.InvalidObjectException if invariants are violated
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        // Read in items array and various fields
+        s.defaultReadObject();
+
+        if (!invariantsSatisfied())
+            throw new java.io.InvalidObjectException("invariants violated");
+    }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java b/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
index 290fee1..8043510 100644
--- a/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -39,10 +39,6 @@
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
-// BEGIN android-note
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
 /**
  * A {@link Deque} that additionally supports blocking operations that wait
  * for the deque to become non-empty when retrieving an element, and wait for
@@ -57,69 +53,69 @@
  * and the fourth blocks for only a given maximum time limit before giving
  * up.  These methods are summarized in the following table:
  *
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <table class="plain">
  * <caption>Summary of BlockingDeque methods</caption>
  *  <tr>
- *    <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
+ *    <th id="First" colspan="5"> First Element (Head)</th>
  *  </tr>
  *  <tr>
  *    <td></td>
- *    <td ALIGN=CENTER><em>Throws exception</em></td>
- *    <td ALIGN=CENTER><em>Special value</em></td>
- *    <td ALIGN=CENTER><em>Blocks</em></td>
- *    <td ALIGN=CENTER><em>Times out</em></td>
+ *    <th id="FThrow" style="font-weight:normal; font-style: italic">Throws exception</th>
+ *    <th id="FValue" style="font-weight:normal; font-style: italic">Special value</th>
+ *    <th id="FBlock" style="font-weight:normal; font-style: italic">Blocks</th>
+ *    <th id="FTimes" style="font-weight:normal; font-style: italic">Times out</th>
  *  </tr>
  *  <tr>
- *    <td><b>Insert</b></td>
- *    <td>{@link #addFirst addFirst(e)}</td>
- *    <td>{@link #offerFirst(Object) offerFirst(e)}</td>
- *    <td>{@link #putFirst putFirst(e)}</td>
- *    <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
+ *    <th id="FInsert" style="text-align:left">Insert</th>
+ *    <td headers="First FInsert FThrow">{@link #addFirst(Object) addFirst(e)}</td>
+ *    <td headers="First FInsert FValue">{@link #offerFirst(Object) offerFirst(e)}</td>
+ *    <td headers="First FInsert FBlock">{@link #putFirst(Object) putFirst(e)}</td>
+ *    <td headers="First FInsert FTimes">{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <td><b>Remove</b></td>
- *    <td>{@link #removeFirst removeFirst()}</td>
- *    <td>{@link #pollFirst pollFirst()}</td>
- *    <td>{@link #takeFirst takeFirst()}</td>
- *    <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *    <th id="FRemove" style="text-align:left">Remove</th>
+ *    <td headers="First FRemove FThrow">{@link #removeFirst() removeFirst()}</td>
+ *    <td headers="First FRemove FValue">{@link #pollFirst() pollFirst()}</td>
+ *    <td headers="First FRemove FBlock">{@link #takeFirst() takeFirst()}</td>
+ *    <td headers="First FRemove FTimes">{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <td><b>Examine</b></td>
- *    <td>{@link #getFirst getFirst()}</td>
- *    <td>{@link #peekFirst peekFirst()}</td>
- *    <td><em>not applicable</em></td>
- *    <td><em>not applicable</em></td>
+ *    <th id="FExamine" style="text-align:left">Examine</th>
+ *    <td headers="First FExamine FThrow">{@link #getFirst() getFirst()}</td>
+ *    <td headers="First FExamine FValue">{@link #peekFirst() peekFirst()}</td>
+ *    <td headers="First FExamine FBlock" style="font-style:italic">not applicable</td>
+ *    <td headers="First FExamine FTimes" style="font-style:italic">not applicable</td>
  *  </tr>
  *  <tr>
- *    <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td>
+ *    <th id="Last" colspan="5"> Last Element (Tail)</th>
  *  </tr>
  *  <tr>
  *    <td></td>
- *    <td ALIGN=CENTER><em>Throws exception</em></td>
- *    <td ALIGN=CENTER><em>Special value</em></td>
- *    <td ALIGN=CENTER><em>Blocks</em></td>
- *    <td ALIGN=CENTER><em>Times out</em></td>
+ *    <th id="LThrow" style="font-weight:normal; font-style: italic">Throws exception</th>
+ *    <th id="LValue" style="font-weight:normal; font-style: italic">Special value</th>
+ *    <th id="LBlock" style="font-weight:normal; font-style: italic">Blocks</th>
+ *    <th id="LTimes" style="font-weight:normal; font-style: italic">Times out</th>
  *  </tr>
  *  <tr>
- *    <td><b>Insert</b></td>
- *    <td>{@link #addLast addLast(e)}</td>
- *    <td>{@link #offerLast(Object) offerLast(e)}</td>
- *    <td>{@link #putLast putLast(e)}</td>
- *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *    <th id="LInsert" style="text-align:left">Insert</th>
+ *    <td headers="Last LInsert LThrow">{@link #addLast(Object) addLast(e)}</td>
+ *    <td headers="Last LInsert LValue">{@link #offerLast(Object) offerLast(e)}</td>
+ *    <td headers="Last LInsert LBlock">{@link #putLast(Object) putLast(e)}</td>
+ *    <td headers="Last LInsert LTimes">{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <td><b>Remove</b></td>
- *    <td>{@link #removeLast() removeLast()}</td>
- *    <td>{@link #pollLast() pollLast()}</td>
- *    <td>{@link #takeLast takeLast()}</td>
- *    <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
+ *    <th id="LRemove" style="text-align:left">Remove</th>
+ *    <td headers="Last LRemove LThrow">{@link #removeLast() removeLast()}</td>
+ *    <td headers="Last LRemove LValue">{@link #pollLast() pollLast()}</td>
+ *    <td headers="Last LRemove LBlock">{@link #takeLast() takeLast()}</td>
+ *    <td headers="Last LRemove LTimes">{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <td><b>Examine</b></td>
- *    <td>{@link #getLast getLast()}</td>
- *    <td>{@link #peekLast peekLast()}</td>
- *    <td><em>not applicable</em></td>
- *    <td><em>not applicable</em></td>
+ *    <th id="LExamine" style="text-align:left">Examine</th>
+ *    <td headers="Last LExamine LThrow">{@link #getLast() getLast()}</td>
+ *    <td headers="Last LExamine LValue">{@link #peekLast() peekLast()}</td>
+ *    <td headers="Last LExamine LBlock" style="font-style:italic">not applicable</td>
+ *    <td headers="Last LExamine LTimes" style="font-style:italic">not applicable</td>
  *  </tr>
  * </table>
  *
@@ -132,60 +128,55 @@
  * {@code BlockingQueue} interface are precisely equivalent to
  * {@code BlockingDeque} methods as indicated in the following table:
  *
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <table class="plain">
  * <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
  *  <tr>
- *    <td ALIGN=CENTER> <b>{@code BlockingQueue} Method</b></td>
- *    <td ALIGN=CENTER> <b>Equivalent {@code BlockingDeque} Method</b></td>
+ *    <td></td>
+ *    <th id="BQueue"> {@code BlockingQueue} Method</th>
+ *    <th id="BDeque"> Equivalent {@code BlockingDeque} Method</th>
  *  </tr>
  *  <tr>
- *    <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
+ *    <th id="Insert" rowspan="4" style="text-align:left; vertical-align:top">Insert</th>
+ *    <th id="add" style="font-weight:normal; text-align:left">{@link #add(Object) add(e)}</th>
+ *    <td headers="Insert BDeque add">{@link #addLast(Object) addLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #add(Object) add(e)}</td>
- *    <td>{@link #addLast(Object) addLast(e)}</td>
+ *    <th id="offer1" style="font-weight:normal; text-align:left">{@link #offer(Object) offer(e)}</th>
+ *    <td headers="Insert BDeque offer1">{@link #offerLast(Object) offerLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #offer(Object) offer(e)}</td>
- *    <td>{@link #offerLast(Object) offerLast(e)}</td>
+ *    <th id="put" style="font-weight:normal; text-align:left">{@link #put(Object) put(e)}</th>
+ *    <td headers="Insert BDeque put">{@link #putLast(Object) putLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #put(Object) put(e)}</td>
- *    <td>{@link #putLast(Object) putLast(e)}</td>
+ *    <th id="offer2" style="font-weight:normal; text-align:left">{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</th>
+ *    <td headers="Insert BDeque offer2">{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
- *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *    <th id="Remove" rowspan="4" style="text-align:left; vertical-align:top">Remove</th>
+ *    <th id="remove" style="font-weight:normal; text-align:left">{@link #remove() remove()}</th>
+ *    <td headers="Remove BDeque remove">{@link #removeFirst() removeFirst()}</td>
  *  </tr>
  *  <tr>
- *    <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>
+ *    <th id="poll1" style="font-weight:normal; text-align:left">{@link #poll() poll()}</th>
+ *    <td headers="Remove BDeque poll1">{@link #pollFirst() pollFirst()}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #remove() remove()}</td>
- *    <td>{@link #removeFirst() removeFirst()}</td>
+ *    <th id="take" style="font-weight:normal; text-align:left">{@link #take() take()}</th>
+ *    <td headers="Remove BDeque take">{@link #takeFirst() takeFirst()}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #poll() poll()}</td>
- *    <td>{@link #pollFirst() pollFirst()}</td>
+ *    <th id="poll2" style="font-weight:normal; text-align:left">{@link #poll(long, TimeUnit) poll(time, unit)}</th>
+ *    <td headers="Remove BDeque poll2">{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #take() take()}</td>
- *    <td>{@link #takeFirst() takeFirst()}</td>
+ *    <th id="Examine" rowspan="2" style="text-align:left; vertical-align:top">Examine</th>
+ *    <th id="element" style="font-weight:normal; text-align:left">{@link #element() element()}</th>
+ *    <td headers="Examine BDeque element">{@link #getFirst() getFirst()}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
- *    <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
- *  </tr>
- *  <tr>
- *    <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td>
- *  </tr>
- *  <tr>
- *    <td>{@link #element() element()}</td>
- *    <td>{@link #getFirst() getFirst()}</td>
- *  </tr>
- *  <tr>
- *    <td>{@link #peek() peek()}</td>
- *    <td>{@link #peekFirst() peekFirst()}</td>
+ *    <th id="peek" style="font-weight:normal; text-align:left">{@link #peek() peek()}</th>
+ *    <td headers="Examine BDeque peek">{@link #peekFirst() peekFirst()}</td>
  *  </tr>
  * </table>
  *
@@ -197,7 +188,7 @@
  * the {@code BlockingDeque} in another thread.
  *
  * <p>This interface is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
  * Java Collections Framework</a>.
  *
  * @since 1.6
@@ -408,9 +399,9 @@
      * @return {@code true} if an element was removed as a result of this call
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this deque
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      */
     boolean removeFirstOccurrence(Object o);
 
@@ -426,9 +417,9 @@
      * @return {@code true} if an element was removed as a result of this call
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this deque
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      */
     boolean removeLastOccurrence(Object o);
 
@@ -516,7 +507,7 @@
     /**
      * Retrieves and removes the head of the queue represented by this deque
      * (in other words, the first element of this deque).
-     * This method differs from {@link #poll poll} only in that it
+     * This method differs from {@link #poll() poll()} only in that it
      * throws an exception if this deque is empty.
      *
      * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
@@ -567,7 +558,7 @@
     /**
      * Retrieves, but does not remove, the head of the queue represented by
      * this deque (in other words, the first element of this deque).
-     * This method differs from {@link #peek peek} only in that it throws an
+     * This method differs from {@link #peek() peek} only in that it throws an
      * exception if this deque is empty.
      *
      * <p>This method is equivalent to {@link #getFirst() getFirst}.
@@ -603,9 +594,9 @@
      * @return {@code true} if this deque changed as a result of the call
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this deque
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object o);
 
@@ -618,9 +609,9 @@
      * @return {@code true} if this deque contains the specified element
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this deque
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      */
     boolean contains(Object o);
 
diff --git a/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
index 6f01b77..6fecc27 100644
--- a/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
@@ -38,16 +38,10 @@
 import java.util.Collection;
 import java.util.Queue;
 
-// BEGIN android-note
-// removed link to collections framework docs from header
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
 /**
- * A {@link java.util.Queue} that additionally supports operations
- * that wait for the queue to become non-empty when retrieving an
- * element, and wait for space to become available in the queue when
- * storing an element.
+ * A {@link Queue} that additionally supports operations that wait for
+ * the queue to become non-empty when retrieving an element, and wait
+ * for space to become available in the queue when storing an element.
  *
  * <p>{@code BlockingQueue} methods come in four forms, with different ways
  * of handling operations that cannot be satisfied immediately, but may be
@@ -58,35 +52,35 @@
  * and the fourth blocks for only a given maximum time limit before giving
  * up.  These methods are summarized in the following table:
  *
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <table class="plain">
  * <caption>Summary of BlockingQueue methods</caption>
  *  <tr>
  *    <td></td>
- *    <td ALIGN=CENTER><em>Throws exception</em></td>
- *    <td ALIGN=CENTER><em>Special value</em></td>
- *    <td ALIGN=CENTER><em>Blocks</em></td>
- *    <td ALIGN=CENTER><em>Times out</em></td>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Throws exception</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Special value</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Blocks</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Times out</th>
  *  </tr>
  *  <tr>
- *    <td><b>Insert</b></td>
- *    <td>{@link #add add(e)}</td>
- *    <td>{@link #offer offer(e)}</td>
- *    <td>{@link #put put(e)}</td>
+ *    <th scope="row" style="text-align:left">Insert</th>
+ *    <td>{@link #add(Object) add(e)}</td>
+ *    <td>{@link #offer(Object) offer(e)}</td>
+ *    <td>{@link #put(Object) put(e)}</td>
  *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <td><b>Remove</b></td>
- *    <td>{@link #remove remove()}</td>
- *    <td>{@link #poll poll()}</td>
- *    <td>{@link #take take()}</td>
+ *    <th scope="row" style="text-align:left">Remove</th>
+ *    <td>{@link #remove() remove()}</td>
+ *    <td>{@link #poll() poll()}</td>
+ *    <td>{@link #take() take()}</td>
  *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
  *  </tr>
  *  <tr>
- *    <td><b>Examine</b></td>
- *    <td>{@link #element element()}</td>
- *    <td>{@link #peek peek()}</td>
- *    <td><em>not applicable</em></td>
- *    <td><em>not applicable</em></td>
+ *    <th scope="row" style="text-align:left">Examine</th>
+ *    <td>{@link #element() element()}</td>
+ *    <td>{@link #peek() peek()}</td>
+ *    <td style="font-style: italic">not applicable</td>
+ *    <td style="font-style: italic">not applicable</td>
  *  </tr>
  * </table>
  *
@@ -104,7 +98,7 @@
  *
  * <p>{@code BlockingQueue} implementations are designed to be used
  * primarily for producer-consumer queues, but additionally support
- * the {@link java.util.Collection} interface.  So, for example, it is
+ * the {@link Collection} interface.  So, for example, it is
  * possible to remove an arbitrary element from a queue using
  * {@code remove(x)}. However, such operations are in general
  * <em>not</em> performed very efficiently, and are intended for only
@@ -174,7 +168,10 @@
  * actions subsequent to the access or removal of that element from
  * the {@code BlockingQueue} in another thread.
  *
- * @since 1.5
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
  */
@@ -304,9 +301,9 @@
      * @return {@code true} if this queue changed as a result of the call
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this queue
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object o);
 
@@ -319,9 +316,9 @@
      * @return {@code true} if this queue contains the specified element
      * @throws ClassCastException if the class of the specified element
      *         is incompatible with this queue
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      */
     boolean contains(Object o);
 
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java b/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
index e98e1be..936ffc3 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.concurrent.locks.LockSupport;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
@@ -110,9 +112,9 @@
  * in a {@link NullPointerException} being thrown.
  *
  * @author Doug Lea
- * @since 1.8
  * @param <T> The result type returned by this future's {@code join}
  * and {@code get} methods
+ * @since 1.8
  */
 public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
 
@@ -125,26 +127,29 @@
      * applies across normal vs exceptional outcomes, sync vs async
      * actions, binary triggers, and various forms of completions.
      *
-     * Non-nullness of field result (set via CAS) indicates done.  An
-     * AltResult is used to box null as a result, as well as to hold
-     * exceptions.  Using a single field makes completion simple to
-     * detect and trigger.  Encoding and decoding is straightforward
-     * but adds to the sprawl of trapping and associating exceptions
-     * with targets.  Minor simplifications rely on (static) NIL (to
-     * box null results) being the only AltResult with a null
-     * exception field, so we don't usually need explicit comparisons.
-     * Even though some of the generics casts are unchecked (see
-     * SuppressWarnings annotations), they are placed to be
-     * appropriate even if checked.
+     * Non-nullness of volatile field "result" indicates done.  It may
+     * be set directly if known to be thread-confined, else via CAS.
+     * An AltResult is used to box null as a result, as well as to
+     * hold exceptions.  Using a single field makes completion simple
+     * to detect and trigger.  Result encoding and decoding is
+     * straightforward but tedious and adds to the sprawl of trapping
+     * and associating exceptions with targets.  Minor simplifications
+     * rely on (static) NIL (to box null results) being the only
+     * AltResult with a null exception field, so we don't usually need
+     * explicit comparisons.  Even though some of the generics casts
+     * are unchecked (see SuppressWarnings annotations), they are
+     * placed to be appropriate even if checked.
      *
      * Dependent actions are represented by Completion objects linked
      * as Treiber stacks headed by field "stack". There are Completion
-     * classes for each kind of action, grouped into single-input
-     * (UniCompletion), two-input (BiCompletion), projected
-     * (BiCompletions using either (not both) of two inputs), shared
-     * (CoCompletion, used by the second of two sources), zero-input
-     * source actions, and Signallers that unblock waiters. Class
-     * Completion extends ForkJoinTask to enable async execution
+     * classes for each kind of action, grouped into:
+     * - single-input (UniCompletion),
+     * - two-input (BiCompletion),
+     * - projected (BiCompletions using exactly one of two inputs),
+     * - shared (CoCompletion, used by the second of two sources),
+     * - zero-input source actions,
+     * - Signallers that unblock waiters.
+     * Class Completion extends ForkJoinTask to enable async execution
      * (adding no space overhead because we exploit its "tag" methods
      * to maintain claims). It is also declared as Runnable to allow
      * usage with arbitrary executors.
@@ -160,7 +165,7 @@
      *   encounter layers of adapters in common usages.
      *
      * * Boolean CompletableFuture method x(...) (for example
-     *   uniApply) takes all of the arguments needed to check that an
+     *   biApply) takes all of the arguments needed to check that an
      *   action is triggerable, and then either runs the action or
      *   arranges its async execution by executing its Completion
      *   argument, if present. The method returns true if known to be
@@ -170,24 +175,32 @@
      *   method with its held arguments, and on success cleans up.
      *   The mode argument allows tryFire to be called twice (SYNC,
      *   then ASYNC); the first to screen and trap exceptions while
-     *   arranging to execute, and the second when called from a
-     *   task. (A few classes are not used async so take slightly
-     *   different forms.)  The claim() callback suppresses function
-     *   invocation if already claimed by another thread.
+     *   arranging to execute, and the second when called from a task.
+     *   (A few classes are not used async so take slightly different
+     *   forms.)  The claim() callback suppresses function invocation
+     *   if already claimed by another thread.
+     *
+     * * Some classes (for example UniApply) have separate handling
+     *   code for when known to be thread-confined ("now" methods) and
+     *   for when shared (in tryFire), for efficiency.
      *
      * * CompletableFuture method xStage(...) is called from a public
-     *   stage method of CompletableFuture x. It screens user
+     *   stage method of CompletableFuture f. It screens user
      *   arguments and invokes and/or creates the stage object.  If
-     *   not async and x is already complete, the action is run
-     *   immediately.  Otherwise a Completion c is created, pushed to
-     *   x's stack (unless done), and started or triggered via
-     *   c.tryFire.  This also covers races possible if x completes
-     *   while pushing.  Classes with two inputs (for example BiApply)
-     *   deal with races across both while pushing actions.  The
-     *   second completion is a CoCompletion pointing to the first,
-     *   shared so that at most one performs the action.  The
-     *   multiple-arity methods allOf and anyOf do this pairwise to
-     *   form trees of completions.
+     *   not async and already triggerable, the action is run
+     *   immediately.  Otherwise a Completion c is created, and
+     *   submitted to the executor if triggerable, or pushed onto f's
+     *   stack if not.  Completion actions are started via c.tryFire.
+     *   We recheck after pushing to a source future's stack to cover
+     *   possible races if the source completes while pushing.
+     *   Classes with two inputs (for example BiApply) deal with races
+     *   across both while pushing actions.  The second completion is
+     *   a CoCompletion pointing to the first, shared so that at most
+     *   one performs the action.  The multiple-arity methods allOf
+     *   does this pairwise to form trees of completions.  Method
+     *   anyOf is handled differently from allOf because completion of
+     *   any source should trigger a cleanStack of other sources.
+     *   Each AnyOf completion can reach others via a shared array.
      *
      * Note that the generic type parameters of methods vary according
      * to whether "this" is a source, dependent, or completion.
@@ -212,29 +225,30 @@
      * pointing back to its sources. So we null out fields as soon as
      * possible.  The screening checks needed anyway harmlessly ignore
      * null arguments that may have been obtained during races with
-     * threads nulling out fields.  We also try to unlink fired
-     * Completions from stacks that might never be popped (see method
-     * postFire).  Completion fields need not be declared as final or
-     * volatile because they are only visible to other threads upon
-     * safe publication.
+     * threads nulling out fields.  We also try to unlink non-isLive
+     * (fired or cancelled) Completions from stacks that might
+     * otherwise never be popped: Method cleanStack always unlinks non
+     * isLive completions from the head of stack; others may
+     * occasionally remain if racing with other cancellations or
+     * removals.
+     *
+     * Completion fields need not be declared as final or volatile
+     * because they are only visible to other threads upon safe
+     * publication.
      */
 
     volatile Object result;       // Either the result or boxed AltResult
     volatile Completion stack;    // Top of Treiber stack of dependent actions
 
     final boolean internalComplete(Object r) { // CAS from null to r
-        return U.compareAndSwapObject(this, RESULT, null, r);
-    }
-
-    final boolean casStack(Completion cmp, Completion val) {
-        return U.compareAndSwapObject(this, STACK, cmp, val);
+        return RESULT.compareAndSet(this, null, r);
     }
 
     /** Returns true if successfully pushed c onto stack. */
     final boolean tryPushStack(Completion c) {
         Completion h = stack;
-        lazySetNext(c, h);
-        return U.compareAndSwapObject(this, STACK, h, c);
+        NEXT.set(c, h);         // CAS piggyback
+        return STACK.compareAndSet(this, h, c);
     }
 
     /** Unconditionally pushes c onto stack, retrying if necessary. */
@@ -254,8 +268,7 @@
 
     /** Completes with the null value, unless already completed. */
     final boolean completeNull() {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      NIL);
+        return RESULT.compareAndSet(this, null, NIL);
     }
 
     /** Returns the encoding of the given non-exceptional value. */
@@ -265,8 +278,7 @@
 
     /** Completes with a non-exceptional result, unless already completed. */
     final boolean completeValue(T t) {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      (t == null) ? NIL : t);
+        return RESULT.compareAndSet(this, null, (t == null) ? NIL : t);
     }
 
     /**
@@ -280,8 +292,7 @@
 
     /** Completes with an exceptional result, unless already completed. */
     final boolean completeThrowable(Throwable x) {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      encodeThrowable(x));
+        return RESULT.compareAndSet(this, null, encodeThrowable(x));
     }
 
     /**
@@ -308,8 +319,7 @@
      * existing CompletionException.
      */
     final boolean completeThrowable(Throwable x, Object r) {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      encodeThrowable(x, r));
+        return RESULT.compareAndSet(this, null, encodeThrowable(x, r));
     }
 
     /**
@@ -327,10 +337,11 @@
      */
     static Object encodeRelay(Object r) {
         Throwable x;
-        return (((r instanceof AltResult) &&
-                 (x = ((AltResult)r).ex) != null &&
-                 !(x instanceof CompletionException)) ?
-                new AltResult(new CompletionException(x)) : r);
+        if (r instanceof AltResult
+            && (x = ((AltResult)r).ex) != null
+            && !(x instanceof CompletionException))
+            r = new AltResult(new CompletionException(x));
+        return r;
     }
 
     /**
@@ -338,14 +349,13 @@
      * If exceptional, r is first coerced to a CompletionException.
      */
     final boolean completeRelay(Object r) {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      encodeRelay(r));
+        return RESULT.compareAndSet(this, null, encodeRelay(r));
     }
 
     /**
      * Reports result using Future.get conventions.
      */
-    private static <T> T reportGet(Object r)
+    private static Object reportGet(Object r)
         throws InterruptedException, ExecutionException {
         if (r == null) // by convention below, null means interrupted
             throw new InterruptedException();
@@ -360,14 +370,13 @@
                 x = cause;
             throw new ExecutionException(x);
         }
-        @SuppressWarnings("unchecked") T t = (T) r;
-        return t;
+        return r;
     }
 
     /**
      * Decodes outcome to return result or throw unchecked exception.
      */
-    private static <T> T reportJoin(Object r) {
+    private static Object reportJoin(Object r) {
         if (r instanceof AltResult) {
             Throwable x;
             if ((x = ((AltResult)r).ex) == null)
@@ -378,8 +387,7 @@
                 throw (CompletionException)x;
             throw new CompletionException(x);
         }
-        @SuppressWarnings("unchecked") T t = (T) r;
-        return t;
+        return r;
     }
 
     /* ------------- Async task preliminaries -------------- */
@@ -425,12 +433,6 @@
     static final int ASYNC  =  1;
     static final int NESTED = -1;
 
-    /**
-     * Spins before blocking in waitingGet
-     */
-    static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ?
-                              1 << 8 : 0);
-
     /* ------------- Base Completion classes and operations -------------- */
 
     @SuppressWarnings("serial")
@@ -455,10 +457,6 @@
         public final void setRawResult(Void v) {}
     }
 
-    static void lazySetNext(Completion c, Completion next) {
-        U.putOrderedObject(c, NEXT, next);
-    }
-
     /**
      * Pops and tries to trigger all reachable dependents.  Call only
      * when known to be done.
@@ -473,40 +471,47 @@
         while ((h = f.stack) != null ||
                (f != this && (h = (f = this).stack) != null)) {
             CompletableFuture<?> d; Completion t;
-            if (f.casStack(h, t = h.next)) {
+            if (STACK.compareAndSet(f, h, t = h.next)) {
                 if (t != null) {
                     if (f != this) {
                         pushStack(h);
                         continue;
                     }
-                    h.next = null;    // detach
+                    NEXT.compareAndSet(h, t, null); // try to detach
                 }
                 f = (d = h.tryFire(NESTED)) == null ? this : d;
             }
         }
     }
 
-    /** Traverses stack and unlinks dead Completions. */
+    /** Traverses stack and unlinks one or more dead Completions, if found. */
     final void cleanStack() {
-        for (Completion p = null, q = stack; q != null;) {
+        Completion p = stack;
+        // ensure head of stack live
+        for (boolean unlinked = false;;) {
+            if (p == null)
+                return;
+            else if (p.isLive()) {
+                if (unlinked)
+                    return;
+                else
+                    break;
+            }
+            else if (STACK.weakCompareAndSet(this, p, (p = p.next)))
+                unlinked = true;
+            else
+                p = stack;
+        }
+        // try to unlink first non-live
+        for (Completion q = p.next; q != null;) {
             Completion s = q.next;
             if (q.isLive()) {
                 p = q;
                 q = s;
-            }
-            else if (p == null) {
-                casStack(q, s);
-                q = stack;
-            }
-            else {
-                p.next = s;
-                if (p.isLive())
-                    q = s;
-                else {
-                    p = null;  // restart
-                    q = stack;
-                }
-            }
+            } else if (NEXT.weakCompareAndSet(p, q, s))
+                break;
+            else
+                q = p.next;
         }
     }
 
@@ -544,24 +549,34 @@
         final boolean isLive() { return dep != null; }
     }
 
-    /** Pushes the given completion (if it exists) unless done. */
-    final void push(UniCompletion<?,?> c) {
+    /**
+     * Pushes the given completion unless it completes while trying.
+     * Caller should first check that result is null.
+     */
+    final void unipush(Completion c) {
         if (c != null) {
-            while (result == null && !tryPushStack(c))
-                lazySetNext(c, null); // clear on failure
+            while (!tryPushStack(c)) {
+                if (result != null) {
+                    NEXT.set(c, null);
+                    break;
+                }
+            }
+            if (result != null)
+                c.tryFire(SYNC);
         }
     }
 
     /**
-     * Post-processing by dependent after successful UniCompletion
-     * tryFire.  Tries to clean stack of source a, and then either runs
-     * postComplete or returns this to caller, depending on mode.
+     * Post-processing by dependent after successful UniCompletion tryFire.
+     * Tries to clean stack of source a, and then either runs postComplete
+     * or returns this to caller, depending on mode.
      */
     final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
         if (a != null && a.stack != null) {
-            if (mode < 0 || a.result == null)
+            Object r;
+            if ((r = a.result) == null)
                 a.cleanStack();
-            else
+            if (mode >= 0 && (r != null || a.result != null))
                 a.postComplete();
         }
         if (result != null && stack != null) {
@@ -583,48 +598,65 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniApply(a = src, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Function<? super T,? extends V> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else {
+                        @SuppressWarnings("unchecked") T t = (T) r;
+                        d.completeValue(f.apply(t));
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniApply(CompletableFuture<S> a,
-                               Function<? super S,? extends T> f,
-                               UniApply<S,T> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            if (r instanceof AltResult) {
-                if ((x = ((AltResult)r).ex) != null) {
-                    completeThrowable(x, r);
-                    break tryComplete;
-                }
-                r = null;
-            }
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                @SuppressWarnings("unchecked") S s = (S) r;
-                completeValue(f.apply(s));
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private <V> CompletableFuture<V> uniApplyStage(
         Executor e, Function<? super T,? extends V> f) {
         if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniApplyNow(r, e, f);
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e != null || !d.uniApply(this, f, null)) {
-            UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
+        unipush(new UniApply<T,V>(e, d, this, f));
+        return d;
+    }
+
+    private <V> CompletableFuture<V> uniApplyNow(
+        Object r, Executor e, Function<? super T,? extends V> f) {
+        Throwable x;
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (r instanceof AltResult) {
+            if ((x = ((AltResult)r).ex) != null) {
+                d.result = encodeThrowable(x, r);
+                return d;
+            }
+            r = null;
+        }
+        try {
+            if (e != null) {
+                e.execute(new UniApply<T,V>(null, d, this, f));
+            } else {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                d.result = d.encodeValue(f.apply(t));
+            }
+        } catch (Throwable ex) {
+            d.result = encodeThrowable(ex);
         }
         return d;
     }
@@ -638,48 +670,67 @@
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniAccept(a = src, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Consumer<? super T> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else {
+                        @SuppressWarnings("unchecked") T t = (T) r;
+                        f.accept(t);
+                        d.completeNull();
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniAccept(CompletableFuture<S> a,
-                                Consumer<? super S> f, UniAccept<S> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            if (r instanceof AltResult) {
-                if ((x = ((AltResult)r).ex) != null) {
-                    completeThrowable(x, r);
-                    break tryComplete;
-                }
-                r = null;
-            }
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                @SuppressWarnings("unchecked") S s = (S) r;
-                f.accept(s);
-                completeNull();
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private CompletableFuture<Void> uniAcceptStage(Executor e,
                                                    Consumer<? super T> f) {
         if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniAcceptNow(r, e, f);
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.uniAccept(this, f, null)) {
-            UniAccept<T> c = new UniAccept<T>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
+        unipush(new UniAccept<T>(e, d, this, f));
+        return d;
+    }
+
+    private CompletableFuture<Void> uniAcceptNow(
+        Object r, Executor e, Consumer<? super T> f) {
+        Throwable x;
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (r instanceof AltResult) {
+            if ((x = ((AltResult)r).ex) != null) {
+                d.result = encodeThrowable(x, r);
+                return d;
+            }
+            r = null;
+        }
+        try {
+            if (e != null) {
+                e.execute(new UniAccept<T>(null, d, this, f));
+            } else {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                f.accept(t);
+                d.result = NIL;
+            }
+        } catch (Throwable ex) {
+            d.result = encodeThrowable(ex);
         }
         return d;
     }
@@ -693,42 +744,56 @@
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniRun(a = src, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Runnable f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            if (d.result == null) {
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                    d.completeThrowable(x, r);
+                else
+                    try {
+                        if (mode <= 0 && !claim())
+                            return null;
+                        else {
+                            f.run();
+                            d.completeNull();
+                        }
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
-        if (result == null) {
-            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                completeThrowable(x, r);
-            else
-                try {
-                    if (c != null && !c.claim())
-                        return false;
-                    f.run();
-                    completeNull();
-                } catch (Throwable ex) {
-                    completeThrowable(ex);
-                }
-        }
-        return true;
-    }
-
     private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
         if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniRunNow(r, e, f);
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.uniRun(this, f, null)) {
-            UniRun<T> c = new UniRun<T>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
-        }
+        unipush(new UniRun<T>(e, d, this, f));
+        return d;
+    }
+
+    private CompletableFuture<Void> uniRunNow(Object r, Executor e, Runnable f) {
+        Throwable x;
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+            d.result = encodeThrowable(x, r);
+        else
+            try {
+                if (e != null) {
+                    e.execute(new UniRun<T>(null, d, this, f));
+                } else {
+                    f.run();
+                    d.result = NIL;
+                }
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
@@ -742,20 +807,20 @@
         }
         final CompletableFuture<T> tryFire(int mode) {
             CompletableFuture<T> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
+            Object r; BiConsumer<? super T, ? super Throwable> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || !d.uniWhenComplete(r, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniWhenComplete(CompletableFuture<T> a,
+    final boolean uniWhenComplete(Object r,
                                   BiConsumer<? super T,? super Throwable> f,
                                   UniWhenComplete<T> c) {
-        Object r; T t; Throwable x = null;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
+        T t; Throwable x = null;
         if (result == null) {
             try {
                 if (c != null && !c.claim())
@@ -787,10 +852,17 @@
         Executor e, BiConsumer<? super T, ? super Throwable> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<T> d = newIncompleteFuture();
-        if (e != null || !d.uniWhenComplete(this, f, null)) {
-            UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniWhenComplete<T>(e, d, this, f));
+        else if (e == null)
+            d.uniWhenComplete(r, f, null);
+        else {
+            try {
+                e.execute(new UniWhenComplete<T>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         }
         return d;
     }
@@ -805,20 +877,20 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniHandle(a = src, fn, mode > 0 ? null : this))
+            Object r; BiFunction<? super T, Throwable, ? extends V> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || !d.uniHandle(r, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniHandle(CompletableFuture<S> a,
+    final <S> boolean uniHandle(Object r,
                                 BiFunction<? super S, Throwable, ? extends T> f,
                                 UniHandle<S,T> c) {
-        Object r; S s; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
+        S s; Throwable x;
         if (result == null) {
             try {
                 if (c != null && !c.claim())
@@ -843,10 +915,17 @@
         Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e != null || !d.uniHandle(this, f, null)) {
-            UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniHandle<T,V>(e, d, this, f));
+        else if (e == null)
+            d.uniHandle(r, f, null);
+        else {
+            try {
+                e.execute(new UniHandle<T,V>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         }
         return d;
     }
@@ -861,19 +940,20 @@
         final CompletableFuture<T> tryFire(int mode) { // never ASYNC
             // assert mode != ASYNC;
             CompletableFuture<T> d; CompletableFuture<T> a;
-            if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
+            Object r; Function<? super Throwable, ? extends T> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || !d.uniExceptionally(r, f, this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniExceptionally(CompletableFuture<T> a,
+    final boolean uniExceptionally(Object r,
                                    Function<? super Throwable, ? extends T> f,
                                    UniExceptionally<T> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
+        Throwable x;
         if (result == null) {
             try {
                 if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
@@ -893,47 +973,39 @@
         Function<Throwable, ? extends T> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<T> d = newIncompleteFuture();
-        if (!d.uniExceptionally(this, f, null)) {
-            UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
-            push(c);
-            c.tryFire(SYNC);
-        }
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniExceptionally<T>(d, this, f));
+        else
+            d.uniExceptionally(r, f, null);
         return d;
     }
 
     @SuppressWarnings("serial")
-    static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
-        UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+    static final class UniRelay<U, T extends U> extends UniCompletion<T,U> {
+        UniRelay(CompletableFuture<U> dep, CompletableFuture<T> src) {
             super(null, dep, src);
         }
-        final CompletableFuture<T> tryFire(int mode) {
-            CompletableFuture<T> d; CompletableFuture<T> a;
-            if ((d = dep) == null || !d.uniRelay(a = src))
+        final CompletableFuture<U> tryFire(int mode) {
+            CompletableFuture<U> d; CompletableFuture<T> a; Object r;
+            if ((d = dep) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            if (d.result == null)
+                d.completeRelay(r);
             src = null; dep = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniRelay(CompletableFuture<T> a) {
+    private static <U, T extends U> CompletableFuture<U> uniCopyStage(
+        CompletableFuture<T> src) {
         Object r;
-        if (a == null || (r = a.result) == null)
-            return false;
-        if (result == null) // no need to claim
-            completeRelay(r);
-        return true;
-    }
-
-    private CompletableFuture<T> uniCopyStage() {
-        Object r;
-        CompletableFuture<T> d = newIncompleteFuture();
-        if ((r = result) != null)
-            d.completeRelay(r);
-        else {
-            UniRelay<T> c = new UniRelay<T>(d, this);
-            push(c);
-            c.tryFire(SYNC);
-        }
+        CompletableFuture<U> d = src.newIncompleteFuture();
+        if ((r = src.result) != null)
+            d.result = encodeRelay(r);
+        else
+            src.unipush(new UniRelay<U,T>(d, src));
         return d;
     }
 
@@ -942,9 +1014,7 @@
         if ((r = result) != null)
             return new MinimalStage<T>(encodeRelay(r));
         MinimalStage<T> d = new MinimalStage<T>();
-        UniRelay<T> c = new UniRelay<T>(d, this);
-        push(c);
-        c.tryFire(SYNC);
+        unipush(new UniRelay<T,T>(d, this));
         return d;
     }
 
@@ -958,54 +1028,48 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniCompose(a = src, fn, mode > 0 ? null : this))
+            Function<? super T, ? extends CompletionStage<V>> f;
+            Object r; Throwable x;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    CompletableFuture<V> g = f.apply(t).toCompletableFuture();
+                    if ((r = g.result) != null)
+                        d.completeRelay(r);
+                    else {
+                        g.unipush(new UniRelay<V,V>(d, g));
+                        if (d.result == null)
+                            return null;
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniCompose(
-        CompletableFuture<S> a,
-        Function<? super S, ? extends CompletionStage<T>> f,
-        UniCompose<S,T> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            if (r instanceof AltResult) {
-                if ((x = ((AltResult)r).ex) != null) {
-                    completeThrowable(x, r);
-                    break tryComplete;
-                }
-                r = null;
-            }
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                @SuppressWarnings("unchecked") S s = (S) r;
-                CompletableFuture<T> g = f.apply(s).toCompletableFuture();
-                if (g.result == null || !uniRelay(g)) {
-                    UniRelay<T> copy = new UniRelay<T>(this, g);
-                    g.push(copy);
-                    copy.tryFire(SYNC);
-                    if (result == null)
-                        return false;
-                }
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private <V> CompletableFuture<V> uniComposeStage(
         Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
         if (f == null) throw new NullPointerException();
-        Object r, s; Throwable x;
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e == null && (r = result) != null) {
+        Object r, s; Throwable x;
+        if ((r = result) == null)
+            unipush(new UniCompose<T,V>(e, d, this, f));
+        else if (e == null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
                     d.result = encodeThrowable(x, r);
@@ -1017,21 +1081,20 @@
                 @SuppressWarnings("unchecked") T t = (T) r;
                 CompletableFuture<V> g = f.apply(t).toCompletableFuture();
                 if ((s = g.result) != null)
-                    d.completeRelay(s);
+                    d.result = encodeRelay(s);
                 else {
-                    UniRelay<V> c = new UniRelay<V>(d, g);
-                    g.push(c);
-                    c.tryFire(SYNC);
+                    g.unipush(new UniRelay<V,V>(d, g));
                 }
-                return d;
             } catch (Throwable ex) {
                 d.result = encodeThrowable(ex);
-                return d;
             }
         }
-        UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
-        push(c);
-        c.tryFire(SYNC);
+        else
+            try {
+                e.execute(new UniCompose<T,V>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
@@ -1061,21 +1124,28 @@
         }
         final boolean isLive() {
             BiCompletion<?,?,?> c;
-            return (c = base) != null && c.dep != null;
+            return (c = base) != null
+                // && c.isLive()
+                && c.dep != null;
         }
     }
 
-    /** Pushes completion to this and b unless both done. */
+    /**
+     * Pushes completion to this and b unless both done.
+     * Caller should first check that either result or b.result is null.
+     */
     final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
         if (c != null) {
-            Object r;
-            while ((r = result) == null && !tryPushStack(c))
-                lazySetNext(c, null); // clear on failure
-            if (b != null && b != this && b.result == null) {
-                Completion q = (r != null) ? c : new CoCompletion(c);
-                while (b.result == null && !b.tryPushStack(q))
-                    lazySetNext(q, null); // clear on failure
+            while (result == null) {
+                if (tryPushStack(c)) {
+                    if (b.result == null)
+                        b.unipush(new CoCompletion(c));
+                    else if (result != null)
+                        c.tryFire(SYNC);
+                    return;
+                }
             }
+            b.unipush(c);
         }
     }
 
@@ -1083,9 +1153,10 @@
     final CompletableFuture<T> postFire(CompletableFuture<?> a,
                                         CompletableFuture<?> b, int mode) {
         if (b != null && b.stack != null) { // clean second source
-            if (mode < 0 || b.result == null)
+            Object r;
+            if ((r = b.result) == null)
                 b.cleanStack();
-            else
+            if (mode >= 0 && (r != null || b.result != null))
                 b.postComplete();
         }
         return postFire(a, mode);
@@ -1103,22 +1174,21 @@
             CompletableFuture<V> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r, s; BiFunction<? super T,? super U,? extends V> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || !d.biApply(r, s, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S> boolean biApply(CompletableFuture<R> a,
-                                CompletableFuture<S> b,
+    final <R,S> boolean biApply(Object r, Object s,
                                 BiFunction<? super R,? super S,? extends T> f,
                                 BiApply<R,S,T> c) {
-        Object r, s; Throwable x;
-        if (a == null || (r = a.result) == null ||
-            b == null || (s = b.result) == null || f == null)
-            return false;
+        Throwable x;
         tryComplete: if (result == null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
@@ -1150,15 +1220,20 @@
     private <U,V> CompletableFuture<V> biApplyStage(
         Executor e, CompletionStage<U> o,
         BiFunction<? super T,? super U,? extends V> f) {
-        CompletableFuture<U> b;
+        CompletableFuture<U> b; Object r, s;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e != null || !d.biApply(this, b, f, null)) {
-            BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
-            bipush(b, c);
-            c.tryFire(SYNC);
-        }
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiApply<T,U,V>(e, d, this, b, f));
+        else if (e == null)
+            d.biApply(r, s, f, null);
+        else
+            try {
+                e.execute(new BiApply<T,U,V>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
@@ -1174,22 +1249,21 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r, s; BiConsumer<? super T,? super U> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || !d.biAccept(r, s, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S> boolean biAccept(CompletableFuture<R> a,
-                                 CompletableFuture<S> b,
+    final <R,S> boolean biAccept(Object r, Object s,
                                  BiConsumer<? super R,? super S> f,
                                  BiAccept<R,S> c) {
-        Object r, s; Throwable x;
-        if (a == null || (r = a.result) == null ||
-            b == null || (s = b.result) == null || f == null)
-            return false;
+        Throwable x;
         tryComplete: if (result == null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
@@ -1222,15 +1296,20 @@
     private <U> CompletableFuture<Void> biAcceptStage(
         Executor e, CompletionStage<U> o,
         BiConsumer<? super T,? super U> f) {
-        CompletableFuture<U> b;
+        CompletableFuture<U> b; Object r, s;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.biAccept(this, b, f, null)) {
-            BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
-            bipush(b, c);
-            c.tryFire(SYNC);
-        }
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiAccept<T,U>(e, d, this, b, f));
+        else if (e == null)
+            d.biAccept(r, s, f, null);
+        else
+            try {
+                e.execute(new BiAccept<T,U>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
@@ -1238,8 +1317,7 @@
     static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
         Runnable fn;
         BiRun(Executor executor, CompletableFuture<Void> dep,
-              CompletableFuture<T> src,
-              CompletableFuture<U> snd,
+              CompletableFuture<T> src, CompletableFuture<U> snd,
               Runnable fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1247,25 +1325,25 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r, s; Runnable f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || !d.biRun(r, s, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
-                        Runnable f, BiRun<?,?> c) {
-        Object r, s; Throwable x;
-        if (a == null || (r = a.result) == null ||
-            b == null || (s = b.result) == null || f == null)
-            return false;
+    final boolean biRun(Object r, Object s, Runnable f, BiRun<?,?> c) {
+        Throwable x; Object z;
         if (result == null) {
-            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                completeThrowable(x, r);
-            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
-                completeThrowable(x, s);
+            if ((r instanceof AltResult
+                 && (x = ((AltResult)(z = r)).ex) != null) ||
+                (s instanceof AltResult
+                 && (x = ((AltResult)(z = s)).ex) != null))
+                completeThrowable(x, z);
             else
                 try {
                     if (c != null && !c.claim())
@@ -1281,52 +1359,52 @@
 
     private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
                                                Runnable f) {
-        CompletableFuture<?> b;
+        CompletableFuture<?> b; Object r, s;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.biRun(this, b, f, null)) {
-            BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
-            bipush(b, c);
-            c.tryFire(SYNC);
-        }
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiRun<>(e, d, this, b, f));
+        else if (e == null)
+            d.biRun(r, s, f, null);
+        else
+            try {
+                e.execute(new BiRun<>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
     @SuppressWarnings("serial")
     static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
         BiRelay(CompletableFuture<Void> dep,
-                CompletableFuture<T> src,
-                CompletableFuture<U> snd) {
+                CompletableFuture<T> src, CompletableFuture<U> snd) {
             super(null, dep, src, snd);
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null || !d.biRelay(a = src, b = snd))
+            Object r, s, z; Throwable x;
+            if ((d = dep) == null
+                || (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null)
                 return null;
+            if (d.result == null) {
+                if ((r instanceof AltResult
+                     && (x = ((AltResult)(z = r)).ex) != null) ||
+                    (s instanceof AltResult
+                     && (x = ((AltResult)(z = s)).ex) != null))
+                    d.completeThrowable(x, z);
+                else
+                    d.completeNull();
+            }
             src = null; snd = null; dep = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
-        Object r, s; Throwable x;
-        if (a == null || (r = a.result) == null ||
-            b == null || (s = b.result) == null)
-            return false;
-        if (result == null) {
-            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                completeThrowable(x, r);
-            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
-                completeThrowable(x, s);
-            else
-                completeNull();
-        }
-        return true;
-    }
-
     /** Recursively constructs a tree of completions. */
     static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
                                            int lo, int hi) {
@@ -1334,39 +1412,44 @@
         if (lo > hi) // empty
             d.result = NIL;
         else {
-            CompletableFuture<?> a, b;
+            CompletableFuture<?> a, b; Object r, s, z; Throwable x;
             int mid = (lo + hi) >>> 1;
             if ((a = (lo == mid ? cfs[lo] :
                       andTree(cfs, lo, mid))) == null ||
                 (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
                       andTree(cfs, mid+1, hi))) == null)
                 throw new NullPointerException();
-            if (!d.biRelay(a, b)) {
-                BiRelay<?,?> c = new BiRelay<>(d, a, b);
-                a.bipush(b, c);
-                c.tryFire(SYNC);
-            }
+            if ((r = a.result) == null || (s = b.result) == null)
+                a.bipush(b, new BiRelay<>(d, a, b));
+            else if ((r instanceof AltResult
+                      && (x = ((AltResult)(z = r)).ex) != null) ||
+                     (s instanceof AltResult
+                      && (x = ((AltResult)(z = s)).ex) != null))
+                d.result = encodeThrowable(x, z);
+            else
+                d.result = NIL;
         }
         return d;
     }
 
     /* ------------- Projected (Ored) BiCompletions -------------- */
 
-    /** Pushes completion to this and b unless either done. */
+    /**
+     * Pushes completion to this and b unless either done.
+     * Caller should first check that result and b.result are both null.
+     */
     final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
         if (c != null) {
-            while ((b == null || b.result == null) && result == null) {
-                if (tryPushStack(c)) {
-                    if (b != null && b != this && b.result == null) {
-                        Completion q = new CoCompletion(c);
-                        while (result == null && b.result == null &&
-                               !b.tryPushStack(q))
-                            lazySetNext(q, null); // clear on failure
-                    }
+            while (!tryPushStack(c)) {
+                if (result != null) {
+                    NEXT.set(c, null);
                     break;
                 }
-                lazySetNext(c, null); // clear on failure
             }
+            if (result != null)
+                c.tryFire(SYNC);
+            else
+                b.unipush(new CoCompletion(c));
         }
     }
 
@@ -1374,8 +1457,7 @@
     static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
         Function<? super T,? extends V> fn;
         OrApply(Executor executor, CompletableFuture<V> dep,
-                CompletableFuture<T> src,
-                CompletableFuture<U> snd,
+                CompletableFuture<T> src, CompletableFuture<U> snd,
                 Function<? super T,? extends V> fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1383,54 +1465,46 @@
             CompletableFuture<V> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Function<? super T,? extends V> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null))
                 return null;
+            tryComplete: if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    if (r instanceof AltResult) {
+                        if ((x = ((AltResult)r).ex) != null) {
+                            d.completeThrowable(x, r);
+                            break tryComplete;
+                        }
+                        r = null;
+                    }
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    d.completeValue(f.apply(t));
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S extends R> boolean orApply(CompletableFuture<R> a,
-                                          CompletableFuture<S> b,
-                                          Function<? super R, ? extends T> f,
-                                          OrApply<R,S,T> c) {
-        Object r; Throwable x;
-        if (a == null || b == null ||
-            ((r = a.result) == null && (r = b.result) == null) || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                if (r instanceof AltResult) {
-                    if ((x = ((AltResult)r).ex) != null) {
-                        completeThrowable(x, r);
-                        break tryComplete;
-                    }
-                    r = null;
-                }
-                @SuppressWarnings("unchecked") R rr = (R) r;
-                completeValue(f.apply(rr));
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private <U extends T,V> CompletableFuture<V> orApplyStage(
-        Executor e, CompletionStage<U> o,
-        Function<? super T, ? extends V> f) {
+        Executor e, CompletionStage<U> o, Function<? super T, ? extends V> f) {
         CompletableFuture<U> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
+
+        Object r; CompletableFuture<? extends T> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniApplyNow(r, e, f);
+
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e != null || !d.orApply(this, b, f, null)) {
-            OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
-            orpush(b, c);
-            c.tryFire(SYNC);
-        }
+        orpush(b, new OrApply<T,U,V>(e, d, this, b, f));
         return d;
     }
 
@@ -1438,8 +1512,7 @@
     static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
         Consumer<? super T> fn;
         OrAccept(Executor executor, CompletableFuture<Void> dep,
-                 CompletableFuture<T> src,
-                 CompletableFuture<U> snd,
+                 CompletableFuture<T> src, CompletableFuture<U> snd,
                  Consumer<? super T> fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1447,54 +1520,47 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Consumer<? super T> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null))
                 return null;
+            tryComplete: if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    if (r instanceof AltResult) {
+                        if ((x = ((AltResult)r).ex) != null) {
+                            d.completeThrowable(x, r);
+                            break tryComplete;
+                        }
+                        r = null;
+                    }
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    f.accept(t);
+                    d.completeNull();
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
-                                           CompletableFuture<S> b,
-                                           Consumer<? super R> f,
-                                           OrAccept<R,S> c) {
-        Object r; Throwable x;
-        if (a == null || b == null ||
-            ((r = a.result) == null && (r = b.result) == null) || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                if (r instanceof AltResult) {
-                    if ((x = ((AltResult)r).ex) != null) {
-                        completeThrowable(x, r);
-                        break tryComplete;
-                    }
-                    r = null;
-                }
-                @SuppressWarnings("unchecked") R rr = (R) r;
-                f.accept(rr);
-                completeNull();
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private <U extends T> CompletableFuture<Void> orAcceptStage(
         Executor e, CompletionStage<U> o, Consumer<? super T> f) {
         CompletableFuture<U> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
+
+        Object r; CompletableFuture<? extends T> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniAcceptNow(r, e, f);
+
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.orAccept(this, b, f, null)) {
-            OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
-            orpush(b, c);
-            c.tryFire(SYNC);
-        }
+        orpush(b, new OrAccept<T,U>(e, d, this, b, f));
         return d;
     }
 
@@ -1502,8 +1568,7 @@
     static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
         Runnable fn;
         OrRun(Executor executor, CompletableFuture<Void> dep,
-              CompletableFuture<T> src,
-              CompletableFuture<U> snd,
+              CompletableFuture<T> src, CompletableFuture<U> snd,
               Runnable fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1511,97 +1576,81 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Runnable f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null))
                 return null;
+            if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else if (r instanceof AltResult
+                        && (x = ((AltResult)r).ex) != null)
+                        d.completeThrowable(x, r);
+                    else {
+                        f.run();
+                        d.completeNull();
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
-                        Runnable f, OrRun<?,?> c) {
-        Object r; Throwable x;
-        if (a == null || b == null ||
-            ((r = a.result) == null && (r = b.result) == null) || f == null)
-            return false;
-        if (result == null) {
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                    completeThrowable(x, r);
-                else {
-                    f.run();
-                    completeNull();
-                }
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
                                                Runnable f) {
         CompletableFuture<?> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
+
+        Object r; CompletableFuture<?> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniRunNow(r, e, f);
+
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.orRun(this, b, f, null)) {
-            OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
-            orpush(b, c);
-            c.tryFire(SYNC);
-        }
+        orpush(b, new OrRun<>(e, d, this, b, f));
         return d;
     }
 
+    /** Completion for an anyOf input future. */
     @SuppressWarnings("serial")
-    static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
-        OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
-                CompletableFuture<U> snd) {
-            super(null, dep, src, snd);
+    static class AnyOf extends Completion {
+        CompletableFuture<Object> dep; CompletableFuture<?> src;
+        CompletableFuture<?>[] srcs;
+        AnyOf(CompletableFuture<Object> dep, CompletableFuture<?> src,
+              CompletableFuture<?>[] srcs) {
+            this.dep = dep; this.src = src; this.srcs = srcs;
         }
         final CompletableFuture<Object> tryFire(int mode) {
-            CompletableFuture<Object> d;
-            CompletableFuture<T> a;
-            CompletableFuture<U> b;
-            if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+            // assert mode != ASYNC;
+            CompletableFuture<Object> d; CompletableFuture<?> a;
+            CompletableFuture<?>[] as;
+            Object r;
+            if ((d = dep) == null
+                || (a = src) == null || (r = a.result) == null
+                || (as = srcs) == null)
                 return null;
-            src = null; snd = null; dep = null;
-            return d.postFire(a, b, mode);
-        }
-    }
-
-    final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
-        Object r;
-        if (a == null || b == null ||
-            ((r = a.result) == null && (r = b.result) == null))
-            return false;
-        if (result == null)
-            completeRelay(r);
-        return true;
-    }
-
-    /** Recursively constructs a tree of completions. */
-    static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
-                                            int lo, int hi) {
-        CompletableFuture<Object> d = new CompletableFuture<Object>();
-        if (lo <= hi) {
-            CompletableFuture<?> a, b;
-            int mid = (lo + hi) >>> 1;
-            if ((a = (lo == mid ? cfs[lo] :
-                      orTree(cfs, lo, mid))) == null ||
-                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
-                      orTree(cfs, mid+1, hi))) == null)
-                throw new NullPointerException();
-            if (!d.orRelay(a, b)) {
-                OrRelay<?,?> c = new OrRelay<>(d, a, b);
-                a.orpush(b, c);
-                c.tryFire(SYNC);
+            dep = null; src = null; srcs = null;
+            if (d.completeRelay(r)) {
+                for (CompletableFuture<?> b : as)
+                    if (b != a)
+                        b.cleanStack();
+                if (mode < 0)
+                    return d;
+                else
+                    d.postComplete();
             }
+            return null;
         }
-        return d;
+        final boolean isLive() {
+            CompletableFuture<Object> d;
+            return (d = dep) != null && d.result == null;
+        }
     }
 
     /* ------------- Zero-input Async forms -------------- */
@@ -1616,7 +1665,7 @@
 
         public final Void getRawResult() { return null; }
         public final void setRawResult(Void v) {}
-        public final boolean exec() { run(); return true; }
+        public final boolean exec() { run(); return false; }
 
         public void run() {
             CompletableFuture<T> d; Supplier<? extends T> f;
@@ -1652,7 +1701,7 @@
 
         public final Void getRawResult() { return null; }
         public final void setRawResult(Void v) {}
-        public final boolean exec() { run(); return true; }
+        public final boolean exec() { run(); return false; }
 
         public void run() {
             CompletableFuture<Void> d; Runnable f;
@@ -1736,15 +1785,13 @@
     private Object waitingGet(boolean interruptible) {
         Signaller q = null;
         boolean queued = false;
-        int spins = SPINS;
         Object r;
         while ((r = result) == null) {
-            if (spins > 0) {
-                if (ThreadLocalRandom.nextSecondarySeed() >= 0)
-                    --spins;
-            }
-            else if (q == null)
+            if (q == null) {
                 q = new Signaller(interruptible, 0L, 0L);
+                if (Thread.currentThread() instanceof ForkJoinWorkerThread)
+                    ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
+            }
             else if (!queued)
                 queued = tryPushStack(q);
             else {
@@ -1757,16 +1804,14 @@
                     break;
             }
         }
-        if (q != null) {
+        if (q != null && queued) {
             q.thread = null;
-            if (q.interrupted) {
-                if (interruptible)
-                    cleanStack();
-                else
-                    Thread.currentThread().interrupt();
-            }
+            if (!interruptible && q.interrupted)
+                Thread.currentThread().interrupt();
+            if (r == null)
+                cleanStack();
         }
-        if (r != null)
+        if (r != null || (r = result) != null)
             postComplete();
         return r;
     }
@@ -1784,9 +1829,12 @@
             Signaller q = null;
             boolean queued = false;
             Object r;
-            while ((r = result) == null) { // similar to untimed, without spins
-                if (q == null)
+            while ((r = result) == null) { // similar to untimed
+                if (q == null) {
                     q = new Signaller(true, nanos, deadline);
+                    if (Thread.currentThread() instanceof ForkJoinWorkerThread)
+                        ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
+                }
                 else if (!queued)
                     queued = tryPushStack(q);
                 else if (q.nanos <= 0L)
@@ -1801,12 +1849,13 @@
                         break;
                 }
             }
-            if (q != null)
+            if (q != null && queued) {
                 q.thread = null;
-            if (r != null)
+                if (r == null)
+                    cleanStack();
+            }
+            if (r != null || (r = result) != null)
                 postComplete();
-            else
-                cleanStack();
             if (r != null || (q != null && q.interrupted))
                 return r;
         }
@@ -1918,9 +1967,12 @@
      * @throws InterruptedException if the current thread was interrupted
      * while waiting
      */
+    @SuppressWarnings("unchecked")
     public T get() throws InterruptedException, ExecutionException {
         Object r;
-        return reportGet((r = result) == null ? waitingGet(true) : r);
+        if ((r = result) == null)
+            r = waitingGet(true);
+        return (T) reportGet(r);
     }
 
     /**
@@ -1936,11 +1988,14 @@
      * while waiting
      * @throws TimeoutException if the wait timed out
      */
+    @SuppressWarnings("unchecked")
     public T get(long timeout, TimeUnit unit)
         throws InterruptedException, ExecutionException, TimeoutException {
-        Object r;
         long nanos = unit.toNanos(timeout);
-        return reportGet((r = result) == null ? timedGet(nanos) : r);
+        Object r;
+        if ((r = result) == null)
+            r = timedGet(nanos);
+        return (T) reportGet(r);
     }
 
     /**
@@ -1957,9 +2012,12 @@
      * @throws CompletionException if this future completed
      * exceptionally or a completion computation threw an exception
      */
+    @SuppressWarnings("unchecked")
     public T join() {
         Object r;
-        return reportJoin((r = result) == null ? waitingGet(false) : r);
+        if ((r = result) == null)
+            r = waitingGet(false);
+        return (T) reportJoin(r);
     }
 
     /**
@@ -1972,9 +2030,10 @@
      * @throws CompletionException if this future completed
      * exceptionally or a completion computation threw an exception
      */
+    @SuppressWarnings("unchecked")
     public T getNow(T valueIfAbsent) {
         Object r;
-        return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
+        return ((r = result) == null) ? valueIfAbsent : (T) reportJoin(r);
     }
 
     /**
@@ -2270,7 +2329,28 @@
      * {@code null}
      */
     public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
-        return orTree(cfs, 0, cfs.length - 1);
+        int n; Object r;
+        if ((n = cfs.length) <= 1)
+            return (n == 0)
+                ? new CompletableFuture<Object>()
+                : uniCopyStage(cfs[0]);
+        for (CompletableFuture<?> cf : cfs)
+            if ((r = cf.result) != null)
+                return new CompletableFuture<Object>(encodeRelay(r));
+        cfs = cfs.clone();
+        CompletableFuture<Object> d = new CompletableFuture<>();
+        for (CompletableFuture<?> cf : cfs)
+            cf.unipush(new AnyOf(d, cf, cfs));
+        // If d was completed while we were adding completions, we should
+        // clean the stack of any sources that may have had completions
+        // pushed on their stack after d was completed.
+        if (d.result != null)
+            for (int i = 0, len = cfs.length; i < len; i++)
+                if (cfs[i].result != null)
+                    for (i++; i < len; i++)
+                        if (cfs[i].result == null)
+                            cfs[i].cleanStack();
+        return d;
     }
 
     /* ------------- Control and status methods -------------- */
@@ -2386,13 +2466,13 @@
         for (Completion p = stack; p != null; p = p.next)
             ++count;
         return super.toString() +
-            ((r == null) ?
-             ((count == 0) ?
-              "[Not completed]" :
-              "[Not completed, " + count + " dependents]") :
-             (((r instanceof AltResult) && ((AltResult)r).ex != null) ?
-              "[Completed exceptionally]" :
-              "[Completed normally]"));
+            ((r == null)
+             ? ((count == 0)
+                ? "[Not completed]"
+                : "[Not completed, " + count + " dependents]")
+             : (((r instanceof AltResult) && ((AltResult)r).ex != null)
+                ? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
+                : "[Completed normally]"));
     }
 
     // jdk9 additions
@@ -2442,7 +2522,7 @@
      * @since 9
      */
     public CompletableFuture<T> copy() {
-        return uniCopyStage();
+        return uniCopyStage(this);
     }
 
     /**
@@ -2455,6 +2535,13 @@
      * exceptionally with a CompletionException with this exception as
      * cause.
      *
+     * <p>Unless overridden by a subclass, a new non-minimal
+     * CompletableFuture with all methods available can be obtained from
+     * a minimal CompletionStage via {@link #toCompletableFuture()}.
+     * For example, completion of a minimal stage can be awaited by
+     *
+     * <pre> {@code minimalStage.toCompletableFuture().join(); }</pre>
+     *
      * @return the new CompletionStage
      * @since 9
      */
@@ -2749,23 +2836,30 @@
         @Override public CompletableFuture<T> completeOnTimeout
             (T value, long timeout, TimeUnit unit) {
             throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> toCompletableFuture() {
+            Object r;
+            if ((r = result) != null)
+                return new CompletableFuture<T>(encodeRelay(r));
+            else {
+                CompletableFuture<T> d = new CompletableFuture<>();
+                unipush(new UniRelay<T,T>(d, this));
+                return d;
+            }
+        }
     }
 
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long RESULT;
-    private static final long STACK;
-    private static final long NEXT;
+    // VarHandle mechanics
+    private static final VarHandle RESULT;
+    private static final VarHandle STACK;
+    private static final VarHandle NEXT;
     static {
         try {
-            RESULT = U.objectFieldOffset
-                (CompletableFuture.class.getDeclaredField("result"));
-            STACK = U.objectFieldOffset
-                (CompletableFuture.class.getDeclaredField("stack"));
-            NEXT = U.objectFieldOffset
-                (Completion.class.getDeclaredField("next"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            RESULT = l.findVarHandle(CompletableFuture.class, "result", Object.class);
+            STACK = l.findVarHandle(CompletableFuture.class, "stack", Completion.class);
+            NEXT = l.findVarHandle(Completion.class, "next", Completion.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletionService.java b/ojluni/src/main/java/java/util/concurrent/CompletionService.java
index f647e21..5e5232e 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletionService.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletionService.java
@@ -57,6 +57,8 @@
  * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
  * actions taken by that task, which in turn <i>happen-before</i>
  * actions following a successful return from the corresponding {@code take()}.
+ *
+ * @since 1.5
  */
 public interface CompletionService<V> {
     /**
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletionStage.java b/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
index d855945..70b601a 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
@@ -856,13 +856,9 @@
      * CompletableFuture, this method may return this stage itself.
      * Otherwise, invocation of this method may be equivalent in
      * effect to {@code thenApply(x -> x)}, but returning an instance
-     * of type {@code CompletableFuture}. A CompletionStage
-     * implementation that does not choose to interoperate with others
-     * may throw {@code UnsupportedOperationException}.
+     * of type {@code CompletableFuture}.
      *
      * @return the CompletableFuture
-     * @throws UnsupportedOperationException if this implementation
-     * does not interoperate with CompletableFuture
      */
     public CompletableFuture<T> toCompletableFuture();
 
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
index 5407963..e43eb7d 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
@@ -68,10 +68,7 @@
 import java.util.function.ToLongBiFunction;
 import java.util.function.ToLongFunction;
 import java.util.stream.Stream;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import jdk.internal.misc.Unsafe;
 
 /**
  * A hash table supporting full concurrency of retrievals and
@@ -162,8 +159,7 @@
  * ordering, or on any other objects or values that may transiently
  * change while computation is in progress; and except for forEach
  * actions, should ideally be side-effect-free. Bulk operations on
- * {@link java.util.Map.Entry} objects do not support method {@code
- * setValue}.
+ * {@link Map.Entry} objects do not support method {@code setValue}.
  *
  * <ul>
  * <li>forEach: Performs a given action on each element.
@@ -256,6 +252,10 @@
  *
  * <p>All arguments to all task methods must be non-null.
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
@@ -297,7 +297,7 @@
      * Table accesses require volatile/atomic reads, writes, and
      * CASes.  Because there is no other way to arrange this without
      * adding further indirections, we use intrinsics
-     * (sun.misc.Unsafe) operations.
+     * (jdk.internal.misc.Unsafe) operations.
      *
      * We use the top (sign) bit of Node hash fields for control
      * purposes -- it is available anyway because of addressing
@@ -628,10 +628,14 @@
         volatile V val;
         volatile Node<K,V> next;
 
-        Node(int hash, K key, V val, Node<K,V> next) {
+        Node(int hash, K key, V val) {
             this.hash = hash;
             this.key = key;
             this.val = val;
+        }
+
+        Node(int hash, K key, V val, Node<K,V> next) {
+            this(hash, key, val);
             this.next = next;
         }
 
@@ -698,12 +702,7 @@
      * See Hackers Delight, sec 3.2
      */
     private static final int tableSizeFor(int c) {
-        int n = c - 1;
-        n |= n >>> 1;
-        n |= n >>> 2;
-        n |= n >>> 4;
-        n |= n >>> 8;
-        n |= n >>> 16;
+        int n = -1 >>> Integer.numberOfLeadingZeros(c - 1);
         return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
     }
 
@@ -713,12 +712,12 @@
      */
     static Class<?> comparableClassFor(Object x) {
         if (x instanceof Comparable) {
-            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
+            Class<?> c; Type[] ts, as; ParameterizedType p;
             if ((c = x.getClass()) == String.class) // bypass checks
                 return c;
             if ((ts = c.getGenericInterfaces()) != null) {
-                for (int i = 0; i < ts.length; ++i) {
-                    if (((t = ts[i]) instanceof ParameterizedType) &&
+                for (Type t : ts) {
+                    if ((t instanceof ParameterizedType) &&
                         ((p = (ParameterizedType)t).getRawType() ==
                          Comparable.class) &&
                         (as = p.getActualTypeArguments()) != null &&
@@ -743,7 +742,7 @@
     /* ---------------- Table element access -------------- */
 
     /*
-     * Volatile access methods are used for table elements as well as
+     * Atomic access methods are used for table elements as well as
      * elements of in-progress next table while resizing.  All uses of
      * the tab arguments must be null checked by callers.  All callers
      * also paranoically precheck that tab's length is not zero (or an
@@ -753,23 +752,21 @@
      * errors by users, these checks must operate on local variables,
      * which accounts for some odd-looking inline assignments below.
      * Note that calls to setTabAt always occur within locked regions,
-     * and so in principle require only release ordering, not
-     * full volatile semantics, but are currently coded as volatile
-     * writes to be conservative.
+     * and so require only release ordering.
      */
 
     @SuppressWarnings("unchecked")
     static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
-        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+        return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
     }
 
     static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
                                         Node<K,V> c, Node<K,V> v) {
-        return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
+        return U.compareAndSetObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
     }
 
     static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
-        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+        U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
     }
 
     /* ---------------- Fields -------------- */
@@ -842,12 +839,7 @@
      * elements is negative
      */
     public ConcurrentHashMap(int initialCapacity) {
-        if (initialCapacity < 0)
-            throw new IllegalArgumentException();
-        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
-                   MAXIMUM_CAPACITY :
-                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
-        this.sizeCtl = cap;
+        this(initialCapacity, LOAD_FACTOR, 1);
     }
 
     /**
@@ -881,8 +873,8 @@
 
     /**
      * Creates a new, empty map with an initial table size based on
-     * the given number of elements ({@code initialCapacity}), table
-     * density ({@code loadFactor}), and number of concurrently
+     * the given number of elements ({@code initialCapacity}), initial
+     * table density ({@code loadFactor}), and number of concurrently
      * updating threads ({@code concurrencyLevel}).
      *
      * @param initialCapacity the initial capacity. The implementation
@@ -1020,16 +1012,20 @@
         int hash = spread(key.hashCode());
         int binCount = 0;
         for (Node<K,V>[] tab = table;;) {
-            Node<K,V> f; int n, i, fh;
+            Node<K,V> f; int n, i, fh; K fk; V fv;
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
-                if (casTabAt(tab, i, null,
-                             new Node<K,V>(hash, key, value, null)))
+                if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
                     break;                   // no lock when adding to empty bin
             }
             else if ((fh = f.hash) == MOVED)
                 tab = helpTransfer(tab, f);
+            else if (onlyIfAbsent // check first node without acquiring lock
+                     && fh == hash
+                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
+                     && (fv = f.val) != null)
+                return fv;
             else {
                 V oldVal = null;
                 synchronized (f) {
@@ -1048,8 +1044,7 @@
                                 }
                                 Node<K,V> pred = e;
                                 if ((e = e.next) == null) {
-                                    pred.next = new Node<K,V>(hash, key,
-                                                              value, null);
+                                    pred.next = new Node<K,V>(hash, key, value);
                                     break;
                                 }
                             }
@@ -1245,7 +1240,8 @@
     @dalvik.annotation.codegen.CovariantReturnType(returnType = KeySetView.class, presentAfter = 28)
     public Set<K> keySet() {
         KeySetView<K,V> ks;
-        return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
+        if ((ks = keySet) != null) return ks;
+        return keySet = new KeySetView<K,V>(this, null);
     }
 
     /**
@@ -1268,7 +1264,8 @@
      */
     public Collection<V> values() {
         ValuesView<K,V> vs;
-        return (vs = values) != null ? vs : (values = new ValuesView<K,V>(this));
+        if ((vs = values) != null) return vs;
+        return values = new ValuesView<K,V>(this);
     }
 
     /**
@@ -1290,7 +1287,8 @@
      */
     public Set<Map.Entry<K,V>> entrySet() {
         EntrySetView<K,V> es;
-        return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K,V>(this));
+        if ((es = entrySet) != null) return es;
+        return entrySet = new EntrySetView<K,V>(this);
     }
 
     /**
@@ -1391,8 +1389,8 @@
     }
 
     /**
-     * Saves the state of the {@code ConcurrentHashMap} instance to a
-     * stream (i.e., serializes it).
+     * Saves this map to a stream (that is, serializes it).
+     *
      * @param s the stream
      * @throws java.io.IOException if an I/O error occurs
      * @serialData
@@ -1436,7 +1434,7 @@
     }
 
     /**
-     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * Reconstitutes this map from a stream (that is, deserializes it).
      * @param s the stream
      * @throws ClassNotFoundException if the class of a serialized object
      *         could not be found
@@ -1470,13 +1468,9 @@
         if (size == 0L)
             sizeCtl = 0;
         else {
-            int n;
-            if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
-                n = MAXIMUM_CAPACITY;
-            else {
-                int sz = (int)size;
-                n = tableSizeFor(sz + (sz >>> 1) + 1);
-            }
+            long ts = (long)(1.0 + size / LOAD_FACTOR);
+            int n = (ts >= (long)MAXIMUM_CAPACITY) ?
+                MAXIMUM_CAPACITY : tableSizeFor((int)ts);
             @SuppressWarnings("unchecked")
             Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
             int mask = n - 1;
@@ -1703,7 +1697,7 @@
         V val = null;
         int binCount = 0;
         for (Node<K,V>[] tab = table;;) {
-            Node<K,V> f; int n, i, fh;
+            Node<K,V> f; int n, i, fh; K fk; V fv;
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
@@ -1714,7 +1708,7 @@
                         Node<K,V> node = null;
                         try {
                             if ((val = mappingFunction.apply(key)) != null)
-                                node = new Node<K,V>(h, key, val, null);
+                                node = new Node<K,V>(h, key, val);
                         } finally {
                             setTabAt(tab, i, node);
                         }
@@ -1725,6 +1719,10 @@
             }
             else if ((fh = f.hash) == MOVED)
                 tab = helpTransfer(tab, f);
+            else if (fh == h    // check first node without acquiring lock
+                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
+                     && (fv = f.val) != null)
+                return fv;
             else {
                 boolean added = false;
                 synchronized (f) {
@@ -1745,7 +1743,7 @@
                                         if (pred.next != null)
                                             throw new IllegalStateException("Recursive update");
                                         added = true;
-                                        pred.next = new Node<K,V>(h, key, val, null);
+                                        pred.next = new Node<K,V>(h, key, val);
                                     }
                                     break;
                                 }
@@ -1914,7 +1912,7 @@
                         try {
                             if ((val = remappingFunction.apply(key, null)) != null) {
                                 delta = 1;
-                                node = new Node<K,V>(h, key, val, null);
+                                node = new Node<K,V>(h, key, val);
                             }
                         } finally {
                             setTabAt(tab, i, node);
@@ -1956,8 +1954,7 @@
                                         if (pred.next != null)
                                             throw new IllegalStateException("Recursive update");
                                         delta = 1;
-                                        pred.next =
-                                            new Node<K,V>(h, key, val, null);
+                                        pred.next = new Node<K,V>(h, key, val);
                                     }
                                     break;
                                 }
@@ -2035,7 +2032,7 @@
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
-                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
+                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value))) {
                     delta = 1;
                     val = value;
                     break;
@@ -2070,8 +2067,7 @@
                                 if ((e = e.next) == null) {
                                     delta = 1;
                                     val = value;
-                                    pred.next =
-                                        new Node<K,V>(h, key, val, null);
+                                    pred.next = new Node<K,V>(h, key, val);
                                     break;
                                 }
                             }
@@ -2232,7 +2228,7 @@
     static final class ForwardingNode<K,V> extends Node<K,V> {
         final Node<K,V>[] nextTable;
         ForwardingNode(Node<K,V>[] tab) {
-            super(MOVED, null, null, null);
+            super(MOVED, null, null);
             this.nextTable = tab;
         }
 
@@ -2268,7 +2264,7 @@
      */
     static final class ReservationNode<K,V> extends Node<K,V> {
         ReservationNode() {
-            super(RESERVED, null, null, null);
+            super(RESERVED, null, null);
         }
 
         Node<K,V> find(int h, Object k) {
@@ -2294,7 +2290,7 @@
         while ((tab = table) == null || tab.length == 0) {
             if ((sc = sizeCtl) < 0)
                 Thread.yield(); // lost initialization race; just spin
-            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+            else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
                 try {
                     if ((tab = table) == null || tab.length == 0) {
                         int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
@@ -2323,15 +2319,15 @@
      * @param check if <0, don't check resize, if <= 1 only check if uncontended
      */
     private final void addCount(long x, int check) {
-        CounterCell[] as; long b, s;
-        if ((as = counterCells) != null ||
-            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
-            CounterCell a; long v; int m;
+        CounterCell[] cs; long b, s;
+        if ((cs = counterCells) != null ||
+            !U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+            CounterCell c; long v; int m;
             boolean uncontended = true;
-            if (as == null || (m = as.length - 1) < 0 ||
-                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
+            if (cs == null || (m = cs.length - 1) < 0 ||
+                (c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
                 !(uncontended =
-                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
+                  U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
                 fullAddCount(x, uncontended);
                 return;
             }
@@ -2349,10 +2345,10 @@
                         sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                         transferIndex <= 0)
                         break;
-                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
+                    if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1))
                         transfer(tab, nt);
                 }
-                else if (U.compareAndSwapInt(this, SIZECTL, sc,
+                else if (U.compareAndSetInt(this, SIZECTL, sc,
                                              (rs << RESIZE_STAMP_SHIFT) + 2))
                     transfer(tab, null);
                 s = sumCount();
@@ -2373,7 +2369,7 @@
                 if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                     sc == rs + MAX_RESIZERS || transferIndex <= 0)
                     break;
-                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
+                if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) {
                     transfer(tab, nextTab);
                     break;
                 }
@@ -2396,7 +2392,7 @@
             Node<K,V>[] tab = table; int n;
             if (tab == null || (n = tab.length) == 0) {
                 n = (sc > c) ? sc : c;
-                if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+                if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
                     try {
                         if (table == tab) {
                             @SuppressWarnings("unchecked")
@@ -2413,7 +2409,7 @@
                 break;
             else if (tab == table) {
                 int rs = resizeStamp(n);
-                if (U.compareAndSwapInt(this, SIZECTL, sc,
+                if (U.compareAndSetInt(this, SIZECTL, sc,
                                         (rs << RESIZE_STAMP_SHIFT) + 2))
                     transfer(tab, null);
             }
@@ -2454,7 +2450,7 @@
                     i = -1;
                     advance = false;
                 }
-                else if (U.compareAndSwapInt
+                else if (U.compareAndSetInt
                          (this, TRANSFERINDEX, nextIndex,
                           nextBound = (nextIndex > stride ?
                                        nextIndex - stride : 0))) {
@@ -2471,7 +2467,7 @@
                     sizeCtl = (n << 1) - (n >>> 1);
                     return;
                 }
-                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
+                if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
                     if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                         return;
                     finishing = advance = true;
@@ -2563,21 +2559,19 @@
      * A padded cell for distributing counts.  Adapted from LongAdder
      * and Striped64.  See their internal docs for explanation.
      */
-    // Android-removed: @Contended, this hint is not used by the Android runtime.
-    //@jdk.internal.vm.annotation.Contended
+    @jdk.internal.vm.annotation.Contended
     static final class CounterCell {
         volatile long value;
         CounterCell(long x) { value = x; }
     }
 
     final long sumCount() {
-        CounterCell[] as = counterCells; CounterCell a;
+        CounterCell[] cs = counterCells;
         long sum = baseCount;
-        if (as != null) {
-            for (int i = 0; i < as.length; ++i) {
-                if ((a = as[i]) != null)
-                    sum += a.value;
-            }
+        if (cs != null) {
+            for (CounterCell c : cs)
+                if (c != null)
+                    sum += c.value;
         }
         return sum;
     }
@@ -2592,13 +2586,13 @@
         }
         boolean collide = false;                // True if last slot nonempty
         for (;;) {
-            CounterCell[] as; CounterCell a; int n; long v;
-            if ((as = counterCells) != null && (n = as.length) > 0) {
-                if ((a = as[(n - 1) & h]) == null) {
+            CounterCell[] cs; CounterCell c; int n; long v;
+            if ((cs = counterCells) != null && (n = cs.length) > 0) {
+                if ((c = cs[(n - 1) & h]) == null) {
                     if (cellsBusy == 0) {            // Try to attach new Cell
                         CounterCell r = new CounterCell(x); // Optimistic create
                         if (cellsBusy == 0 &&
-                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                            U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
                             boolean created = false;
                             try {               // Recheck under lock
                                 CounterCell[] rs; int m, j;
@@ -2620,21 +2614,17 @@
                 }
                 else if (!wasUncontended)       // CAS already known to fail
                     wasUncontended = true;      // Continue after rehash
-                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
+                else if (U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))
                     break;
-                else if (counterCells != as || n >= NCPU)
+                else if (counterCells != cs || n >= NCPU)
                     collide = false;            // At max size or stale
                 else if (!collide)
                     collide = true;
                 else if (cellsBusy == 0 &&
-                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                         U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
                     try {
-                        if (counterCells == as) {// Expand table unless stale
-                            CounterCell[] rs = new CounterCell[n << 1];
-                            for (int i = 0; i < n; ++i)
-                                rs[i] = as[i];
-                            counterCells = rs;
-                        }
+                        if (counterCells == cs) // Expand table unless stale
+                            counterCells = Arrays.copyOf(cs, n << 1);
                     } finally {
                         cellsBusy = 0;
                     }
@@ -2643,11 +2633,11 @@
                 }
                 h = ThreadLocalRandom.advanceProbe(h);
             }
-            else if (cellsBusy == 0 && counterCells == as &&
-                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+            else if (cellsBusy == 0 && counterCells == cs &&
+                     U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
                 boolean init = false;
                 try {                           // Initialize table
-                    if (counterCells == as) {
+                    if (counterCells == cs) {
                         CounterCell[] rs = new CounterCell[2];
                         rs[h & 1] = new CounterCell(x);
                         counterCells = rs;
@@ -2659,7 +2649,7 @@
                 if (init)
                     break;
             }
-            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
+            else if (U.compareAndSetLong(this, BASECOUNT, v = baseCount, v + x))
                 break;                          // Fall back on using base
         }
     }
@@ -2697,12 +2687,12 @@
     }
 
     /**
-     * Returns a list on non-TreeNodes replacing those in given list.
+     * Returns a list of non-TreeNodes replacing those in given list.
      */
     static <K,V> Node<K,V> untreeify(Node<K,V> b) {
         Node<K,V> hd = null, tl = null;
         for (Node<K,V> q = b; q != null; q = q.next) {
-            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val, null);
+            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val);
             if (tl == null)
                 hd = p;
             else
@@ -2808,7 +2798,7 @@
          * Creates bin with initial set of nodes headed by b.
          */
         TreeBin(TreeNode<K,V> b) {
-            super(TREEBIN, null, null, null);
+            super(TREEBIN, null, null);
             this.first = b;
             TreeNode<K,V> r = null;
             for (TreeNode<K,V> x = b, next; x != null; x = next) {
@@ -2855,7 +2845,7 @@
          * Acquires write lock for tree restructuring.
          */
         private final void lockRoot() {
-            if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
+            if (!U.compareAndSetInt(this, LOCKSTATE, 0, WRITER))
                 contendedLock(); // offload to separate method
         }
 
@@ -2873,14 +2863,14 @@
             boolean waiting = false;
             for (int s;;) {
                 if (((s = lockState) & ~WAITER) == 0) {
-                    if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
+                    if (U.compareAndSetInt(this, LOCKSTATE, s, WRITER)) {
                         if (waiting)
                             waiter = null;
                         return;
                     }
                 }
                 else if ((s & WAITER) == 0) {
-                    if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
+                    if (U.compareAndSetInt(this, LOCKSTATE, s, s | WAITER)) {
                         waiting = true;
                         waiter = Thread.currentThread();
                     }
@@ -2905,7 +2895,7 @@
                             return e;
                         e = e.next;
                     }
-                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
+                    else if (U.compareAndSetInt(this, LOCKSTATE, s,
                                                  s + READER)) {
                         TreeNode<K,V> r, p;
                         try {
@@ -3302,16 +3292,9 @@
             return true;
         }
 
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-        private static final long LOCKSTATE;
-        static {
-            try {
-                LOCKSTATE = U.objectFieldOffset
-                    (TreeBin.class.getDeclaredField("lockState"));
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-        }
+        private static final Unsafe U = Unsafe.getUnsafe();
+        private static final long LOCKSTATE
+                = U.objectFieldOffset(TreeBin.class, "lockState");
     }
 
     /* ----------------Table Traversal -------------- */
@@ -3465,9 +3448,9 @@
 
     static final class KeyIterator<K,V> extends BaseIterator<K,V>
         implements Iterator<K>, Enumeration<K> {
-        KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
+        KeyIterator(Node<K,V>[] tab, int size, int index, int limit,
                     ConcurrentHashMap<K,V> map) {
-            super(tab, index, size, limit, map);
+            super(tab, size, index, limit, map);
         }
 
         public final K next() {
@@ -3485,9 +3468,9 @@
 
     static final class ValueIterator<K,V> extends BaseIterator<K,V>
         implements Iterator<V>, Enumeration<V> {
-        ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
+        ValueIterator(Node<K,V>[] tab, int size, int index, int limit,
                       ConcurrentHashMap<K,V> map) {
-            super(tab, index, size, limit, map);
+            super(tab, size, index, limit, map);
         }
 
         public final V next() {
@@ -3505,9 +3488,9 @@
 
     static final class EntryIterator<K,V> extends BaseIterator<K,V>
         implements Iterator<Map.Entry<K,V>> {
-        EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
+        EntryIterator(Node<K,V>[] tab, int size, int index, int limit,
                       ConcurrentHashMap<K,V> map) {
-            super(tab, index, size, limit, map);
+            super(tab, size, index, limit, map);
         }
 
         public final Map.Entry<K,V> next() {
@@ -4558,14 +4541,24 @@
             return true;
         }
 
-        public final boolean removeAll(Collection<?> c) {
+        public boolean removeAll(Collection<?> c) {
             if (c == null) throw new NullPointerException();
             boolean modified = false;
-            for (Iterator<E> it = iterator(); it.hasNext();) {
-                if (c.contains(it.next())) {
-                    it.remove();
-                    modified = true;
+            // Use (c instanceof Set) as a hint that lookup in c is as
+            // efficient as this view
+            Node<K,V>[] t;
+            if ((t = map.table) == null) {
+                return false;
+            } else if (c instanceof Set<?> && c.size() > t.length) {
+                for (Iterator<?> it = iterator(); it.hasNext(); ) {
+                    if (c.contains(it.next())) {
+                        it.remove();
+                        modified = true;
+                    }
                 }
+            } else {
+                for (Object e : c)
+                    modified |= remove(e);
             }
             return modified;
         }
@@ -4751,6 +4744,18 @@
             throw new UnsupportedOperationException();
         }
 
+        @Override public boolean removeAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            for (Iterator<V> it = iterator(); it.hasNext();) {
+                if (c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
         public boolean removeIf(Predicate<? super V> filter) {
             return map.removeValueIf(filter);
         }
@@ -6344,7 +6349,7 @@
     }
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final Unsafe U = Unsafe.getUnsafe();
     private static final long SIZECTL;
     private static final long TRANSFERINDEX;
     private static final long BASECOUNT;
@@ -6354,30 +6359,29 @@
     private static final int ASHIFT;
 
     static {
-        try {
-            SIZECTL = U.objectFieldOffset
-                (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
-            TRANSFERINDEX = U.objectFieldOffset
-                (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
-            BASECOUNT = U.objectFieldOffset
-                (ConcurrentHashMap.class.getDeclaredField("baseCount"));
-            CELLSBUSY = U.objectFieldOffset
-                (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
+        SIZECTL = U.objectFieldOffset
+            (ConcurrentHashMap.class, "sizeCtl");
+        TRANSFERINDEX = U.objectFieldOffset
+            (ConcurrentHashMap.class, "transferIndex");
+        BASECOUNT = U.objectFieldOffset
+            (ConcurrentHashMap.class, "baseCount");
+        CELLSBUSY = U.objectFieldOffset
+            (ConcurrentHashMap.class, "cellsBusy");
 
-            CELLVALUE = U.objectFieldOffset
-                (CounterCell.class.getDeclaredField("value"));
+        CELLVALUE = U.objectFieldOffset
+            (CounterCell.class, "value");
 
-            ABASE = U.arrayBaseOffset(Node[].class);
-            int scale = U.arrayIndexScale(Node[].class);
-            if ((scale & (scale - 1)) != 0)
-                throw new Error("array index scale not a power of two");
-            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
-        } catch (ReflectiveOperationException e) {
-            throw new Error(e);
-        }
+        ABASE = U.arrayBaseOffset(Node[].class);
+        int scale = U.arrayIndexScale(Node[].class);
+        if ((scale & (scale - 1)) != 0)
+            throw new ExceptionInInitializerError("array index scale not a power of two");
+        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
 
         // Reduce the risk of rare disastrous classloading in first call to
         // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
         Class<?> ensureLoaded = LockSupport.class;
+
+        // Eager class load observed to help JIT during startup
+        ensureLoaded = ReservationNode.class;
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
index 3edde54..91ddabd 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractCollection;
 import java.util.Arrays;
 import java.util.Collection;
@@ -46,10 +48,7 @@
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
 
 /**
  * An unbounded concurrent {@linkplain Deque deque} based on linked nodes.
@@ -68,12 +67,12 @@
  * asynchronous nature of these deques, determining the current number
  * of elements requires a traversal of the elements, and so may report
  * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code addAll},
- * {@code removeAll}, {@code retainAll}, {@code containsAll},
- * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
- * to be performed atomically. For example, an iterator operating
- * concurrently with an {@code addAll} operation might view only some
- * of the added elements.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe only some of the added elements.
  *
  * <p>This class and its iterator implement all of the <em>optional</em>
  * methods of the {@link Deque} and {@link Iterator} interfaces.
@@ -85,6 +84,10 @@
  * actions subsequent to the access or removal of that element from
  * the {@code ConcurrentLinkedDeque} in another thread.
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @since 1.7
  * @author Doug Lea
  * @author Martin Buchholz
@@ -228,15 +231,16 @@
      *
      * The implementation is completely directionally symmetrical,
      * except that most public methods that iterate through the list
-     * follow next pointers ("forward" direction).
+     * follow next pointers, in the "forward" direction.
      *
-     * We believe (without full proof) that all single-element deque
-     * operations (e.g., addFirst, peekLast, pollLast) are linearizable
-     * (see Herlihy and Shavit's book).  However, some combinations of
+     * We believe (without full proof) that all single-element Deque
+     * operations that operate directly at the two ends of the Deque
+     * (e.g., addFirst, peekLast, pollLast) are linearizable (see
+     * Herlihy and Shavit's book).  However, some combinations of
      * operations are known not to be linearizable.  In particular,
-     * when an addFirst(A) is racing with pollFirst() removing B, it is
-     * possible for an observer iterating over the elements to observe
-     * A B C and subsequently observe A C, even though no interior
+     * when an addFirst(A) is racing with pollFirst() removing B, it
+     * is possible for an observer iterating over the elements to
+     * observe first [A B C] and then [A C], even though no interior
      * removes are ever performed.  Nevertheless, iterators behave
      * reasonably, providing the "weakly consistent" guarantees.
      *
@@ -292,64 +296,23 @@
         volatile Node<E> prev;
         volatile E item;
         volatile Node<E> next;
+    }
 
-        Node() {  // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
-        }
-
-        /**
-         * Constructs a new node.  Uses relaxed write because item can
-         * only be seen after publication via casNext or casPrev.
-         */
-        Node(E item) {
-            U.putObject(this, ITEM, item);
-        }
-
-        boolean casItem(E cmp, E val) {
-            return U.compareAndSwapObject(this, ITEM, cmp, val);
-        }
-
-        void lazySetNext(Node<E> val) {
-            U.putOrderedObject(this, NEXT, val);
-        }
-
-        boolean casNext(Node<E> cmp, Node<E> val) {
-            return U.compareAndSwapObject(this, NEXT, cmp, val);
-        }
-
-        void lazySetPrev(Node<E> val) {
-            U.putOrderedObject(this, PREV, val);
-        }
-
-        boolean casPrev(Node<E> cmp, Node<E> val) {
-            return U.compareAndSwapObject(this, PREV, cmp, val);
-        }
-
-        // Unsafe mechanics
-
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-        private static final long PREV;
-        private static final long ITEM;
-        private static final long NEXT;
-
-        static {
-            try {
-                PREV = U.objectFieldOffset
-                    (Node.class.getDeclaredField("prev"));
-                ITEM = U.objectFieldOffset
-                    (Node.class.getDeclaredField("item"));
-                NEXT = U.objectFieldOffset
-                    (Node.class.getDeclaredField("next"));
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-        }
+    /**
+     * Returns a new node holding item.  Uses relaxed write because item
+     * can only be seen after piggy-backing publication via CAS.
+     */
+    static <E> Node<E> newNode(E item) {
+        Node<E> node = new Node<E>();
+        ITEM.set(node, item);
+        return node;
     }
 
     /**
      * Links e as first element.
      */
     private void linkFirst(E e) {
-        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
 
         restartFromHead:
         for (;;)
@@ -363,13 +326,13 @@
                     continue restartFromHead;
                 else {
                     // p is first node
-                    newNode.lazySetNext(p); // CAS piggyback
-                    if (p.casPrev(null, newNode)) {
+                    NEXT.set(newNode, p); // CAS piggyback
+                    if (PREV.compareAndSet(p, null, newNode)) {
                         // Successful CAS is the linearization point
                         // for e to become an element of this deque,
                         // and for newNode to become "live".
-                        if (p != h) // hop two nodes at a time
-                            casHead(h, newNode);  // Failure is OK.
+                        if (p != h) // hop two nodes at a time; failure is OK
+                            HEAD.weakCompareAndSet(this, h, newNode);
                         return;
                     }
                     // Lost CAS race to another thread; re-read prev
@@ -381,7 +344,7 @@
      * Links e as last element.
      */
     private void linkLast(E e) {
-        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
 
         restartFromTail:
         for (;;)
@@ -395,13 +358,13 @@
                     continue restartFromTail;
                 else {
                     // p is last node
-                    newNode.lazySetPrev(p); // CAS piggyback
-                    if (p.casNext(null, newNode)) {
+                    PREV.set(newNode, p); // CAS piggyback
+                    if (NEXT.compareAndSet(p, null, newNode)) {
                         // Successful CAS is the linearization point
                         // for e to become an element of this deque,
                         // and for newNode to become "live".
-                        if (p != t) // hop two nodes at a time
-                            casTail(t, newNode);  // Failure is OK.
+                        if (p != t) // hop two nodes at a time; failure is OK
+                            TAIL.weakCompareAndSet(this, t, newNode);
                         return;
                     }
                     // Lost CAS race to another thread; re-read next
@@ -516,8 +479,8 @@
                 updateTail(); // Ensure x is not reachable from tail
 
                 // Finally, actually gc-unlink
-                x.lazySetPrev(isFirst ? prevTerminator() : x);
-                x.lazySetNext(isLast  ? nextTerminator() : x);
+                PREV.setRelease(x, isFirst ? prevTerminator() : x);
+                NEXT.setRelease(x, isLast  ? nextTerminator() : x);
             }
         }
     }
@@ -531,7 +494,8 @@
         // assert first.item == null;
         for (Node<E> o = null, p = next, q;;) {
             if (p.item != null || (q = p.next) == null) {
-                if (o != null && p.prev != p && first.casNext(next, p)) {
+                if (o != null && p.prev != p &&
+                    NEXT.compareAndSet(first, next, p)) {
                     skipDeletedPredecessors(p);
                     if (first.prev == null &&
                         (p.next == null || p.item != null) &&
@@ -541,8 +505,8 @@
                         updateTail(); // Ensure o is not reachable from tail
 
                         // Finally, actually gc-unlink
-                        o.lazySetNext(o);
-                        o.lazySetPrev(prevTerminator());
+                        NEXT.setRelease(o, o);
+                        PREV.setRelease(o, prevTerminator());
                     }
                 }
                 return;
@@ -565,7 +529,8 @@
         // assert last.item == null;
         for (Node<E> o = null, p = prev, q;;) {
             if (p.item != null || (q = p.prev) == null) {
-                if (o != null && p.next != p && last.casPrev(prev, p)) {
+                if (o != null && p.next != p &&
+                    PREV.compareAndSet(last, prev, p)) {
                     skipDeletedSuccessors(p);
                     if (last.next == null &&
                         (p.prev == null || p.item != null) &&
@@ -575,8 +540,8 @@
                         updateTail(); // Ensure o is not reachable from tail
 
                         // Finally, actually gc-unlink
-                        o.lazySetPrev(o);
-                        o.lazySetNext(nextTerminator());
+                        PREV.setRelease(o, o);
+                        NEXT.setRelease(o, nextTerminator());
                     }
                 }
                 return;
@@ -607,7 +572,7 @@
                     (q = (p = q).prev) == null) {
                     // It is possible that p is PREV_TERMINATOR,
                     // but if so, the CAS is guaranteed to fail.
-                    if (casHead(h, p))
+                    if (HEAD.compareAndSet(this, h, p))
                         return;
                     else
                         continue restartFromHead;
@@ -637,7 +602,7 @@
                     (q = (p = q).next) == null) {
                     // It is possible that p is NEXT_TERMINATOR,
                     // but if so, the CAS is guaranteed to fail.
-                    if (casTail(t, p))
+                    if (TAIL.compareAndSet(this, t, p))
                         return;
                     else
                         continue restartFromTail;
@@ -675,7 +640,7 @@
             }
 
             // found active CAS target
-            if (prev == p || x.casPrev(prev, p))
+            if (prev == p || PREV.compareAndSet(x, prev, p))
                 return;
 
         } while (x.item != null || x.next == null);
@@ -706,7 +671,7 @@
             }
 
             // found active CAS target
-            if (next == p || x.casNext(next, p))
+            if (next == p || NEXT.compareAndSet(x, next, p))
                 return;
 
         } while (x.item != null || x.prev == null);
@@ -719,8 +684,9 @@
      */
     final Node<E> succ(Node<E> p) {
         // TODO: should we skip deleted nodes here?
-        Node<E> q = p.next;
-        return (p == q) ? first() : q;
+        if (p == (p = p.next))
+            p = first();
+        return p;
     }
 
     /**
@@ -729,8 +695,9 @@
      * stale pointer that is now off the list.
      */
     final Node<E> pred(Node<E> p) {
-        Node<E> q = p.prev;
-        return (p == q) ? last() : q;
+        if (p == (p = p.prev))
+            p = last();
+        return p;
     }
 
     /**
@@ -751,7 +718,7 @@
                 else if (p == h
                          // It is possible that p is PREV_TERMINATOR,
                          // but if so, the CAS is guaranteed to fail.
-                         || casHead(h, p))
+                         || HEAD.compareAndSet(this, h, p))
                     return p;
                 else
                     continue restartFromHead;
@@ -776,7 +743,7 @@
                 else if (p == t
                          // It is possible that p is NEXT_TERMINATOR,
                          // but if so, the CAS is guaranteed to fail.
-                         || casTail(t, p))
+                         || TAIL.compareAndSet(this, t, p))
                     return p;
                 else
                     continue restartFromTail;
@@ -802,7 +769,7 @@
      * Constructs an empty deque.
      */
     public ConcurrentLinkedDeque() {
-        head = tail = new Node<E>(null);
+        head = tail = new Node<E>();
     }
 
     /**
@@ -818,12 +785,12 @@
         // Copy c into a private chain of Nodes
         Node<E> h = null, t = null;
         for (E e : c) {
-            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
             if (h == null)
                 h = t = newNode;
             else {
-                t.lazySetNext(newNode);
-                newNode.lazySetPrev(t);
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
                 t = newNode;
             }
         }
@@ -836,12 +803,12 @@
     private void initHeadTail(Node<E> h, Node<E> t) {
         if (h == t) {
             if (h == null)
-                h = t = new Node<E>(null);
+                h = t = new Node<E>();
             else {
                 // Avoid edge case of a single Node with non-null item.
-                Node<E> newNode = new Node<E>(null);
-                t.lazySetNext(newNode);
-                newNode.lazySetPrev(t);
+                Node<E> newNode = new Node<E>();
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
                 t = newNode;
             }
         }
@@ -900,21 +867,33 @@
     }
 
     public E peekFirst() {
-        for (Node<E> p = first(); p != null; p = succ(p)) {
-            E item = p.item;
-            if (item != null)
-                return item;
+        restart: for (;;) {
+            E item;
+            Node<E> first = first(), p = first;
+            while ((item = p.item) == null) {
+                if (p == (p = p.next)) continue restart;
+                if (p == null)
+                    break;
+            }
+            // recheck for linearizability
+            if (first.prev != null) continue restart;
+            return item;
         }
-        return null;
     }
 
     public E peekLast() {
-        for (Node<E> p = last(); p != null; p = pred(p)) {
-            E item = p.item;
-            if (item != null)
-                return item;
+        restart: for (;;) {
+            E item;
+            Node<E> last = last(), p = last;
+            while ((item = p.item) == null) {
+                if (p == (p = p.prev)) continue restart;
+                if (p == null)
+                    break;
+            }
+            // recheck for linearizability
+            if (last.next != null) continue restart;
+            return item;
         }
-        return null;
     }
 
     /**
@@ -932,25 +911,45 @@
     }
 
     public E pollFirst() {
-        for (Node<E> p = first(); p != null; p = succ(p)) {
-            E item = p.item;
-            if (item != null && p.casItem(item, null)) {
-                unlink(p);
-                return item;
+        restart: for (;;) {
+            for (Node<E> first = first(), p = first;;) {
+                final E item;
+                if ((item = p.item) != null) {
+                    // recheck for linearizability
+                    if (first.prev != null) continue restart;
+                    if (ITEM.compareAndSet(p, item, null)) {
+                        unlink(p);
+                        return item;
+                    }
+                }
+                if (p == (p = p.next)) continue restart;
+                if (p == null) {
+                    if (first.prev != null) continue restart;
+                    return null;
+                }
             }
         }
-        return null;
     }
 
     public E pollLast() {
-        for (Node<E> p = last(); p != null; p = pred(p)) {
-            E item = p.item;
-            if (item != null && p.casItem(item, null)) {
-                unlink(p);
-                return item;
+        restart: for (;;) {
+            for (Node<E> last = last(), p = last;;) {
+                final E item;
+                if ((item = p.item) != null) {
+                    // recheck for linearizability
+                    if (last.next != null) continue restart;
+                    if (ITEM.compareAndSet(p, item, null)) {
+                        unlink(p);
+                        return item;
+                    }
+                }
+                if (p == (p = p.prev)) continue restart;
+                if (p == null) {
+                    if (last.next != null) continue restart;
+                    return null;
+                }
             }
         }
-        return null;
     }
 
     /**
@@ -1030,8 +1029,10 @@
     public boolean removeFirstOccurrence(Object o) {
         Objects.requireNonNull(o);
         for (Node<E> p = first(); p != null; p = succ(p)) {
-            E item = p.item;
-            if (item != null && o.equals(item) && p.casItem(item, null)) {
+            final E item;
+            if ((item = p.item) != null
+                && o.equals(item)
+                && ITEM.compareAndSet(p, item, null)) {
                 unlink(p);
                 return true;
             }
@@ -1054,8 +1055,10 @@
     public boolean removeLastOccurrence(Object o) {
         Objects.requireNonNull(o);
         for (Node<E> p = last(); p != null; p = pred(p)) {
-            E item = p.item;
-            if (item != null && o.equals(item) && p.casItem(item, null)) {
+            final E item;
+            if ((item = p.item) != null
+                && o.equals(item)
+                && ITEM.compareAndSet(p, item, null)) {
                 unlink(p);
                 return true;
             }
@@ -1074,8 +1077,8 @@
     public boolean contains(Object o) {
         if (o != null) {
             for (Node<E> p = first(); p != null; p = succ(p)) {
-                E item = p.item;
-                if (item != null && o.equals(item))
+                final E item;
+                if ((item = p.item) != null && o.equals(item))
                     return true;
             }
         }
@@ -1108,14 +1111,14 @@
      * @return the number of elements in this deque
      */
     public int size() {
-        restartFromHead: for (;;) {
+        restart: for (;;) {
             int count = 0;
             for (Node<E> p = first(); p != null;) {
                 if (p.item != null)
                     if (++count == Integer.MAX_VALUE)
                         break;  // @see Collection.size()
                 if (p == (p = p.next))
-                    continue restartFromHead;
+                    continue restart;
             }
             return count;
         }
@@ -1159,12 +1162,12 @@
         // Copy c into a private chain of Nodes
         Node<E> beginningOfTheEnd = null, last = null;
         for (E e : c) {
-            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
             if (beginningOfTheEnd == null)
                 beginningOfTheEnd = last = newNode;
             else {
-                last.lazySetNext(newNode);
-                newNode.lazySetPrev(last);
+                NEXT.set(last, newNode);
+                PREV.set(newNode, last);
                 last = newNode;
             }
         }
@@ -1184,16 +1187,16 @@
                     continue restartFromTail;
                 else {
                     // p is last node
-                    beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
-                    if (p.casNext(null, beginningOfTheEnd)) {
+                    PREV.set(beginningOfTheEnd, p); // CAS piggyback
+                    if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
                         // Successful CAS is the linearization point
                         // for all elements to be added to this deque.
-                        if (!casTail(t, last)) {
+                        if (!TAIL.weakCompareAndSet(this, t, last)) {
                             // Try a little harder to update tail,
                             // since we may be adding many elements.
                             t = tail;
                             if (last.next == null)
-                                casTail(t, last);
+                                TAIL.weakCompareAndSet(this, t, last);
                         }
                         return true;
                     }
@@ -1212,12 +1215,12 @@
 
     public String toString() {
         String[] a = null;
-        restartFromHead: for (;;) {
+        restart: for (;;) {
             int charLength = 0;
             int size = 0;
             for (Node<E> p = first(); p != null;) {
-                E item = p.item;
-                if (item != null) {
+                final E item;
+                if ((item = p.item) != null) {
                     if (a == null)
                         a = new String[4];
                     else if (size == a.length)
@@ -1227,7 +1230,7 @@
                     charLength += s.length();
                 }
                 if (p == (p = p.next))
-                    continue restartFromHead;
+                    continue restart;
             }
 
             if (size == 0)
@@ -1239,11 +1242,11 @@
 
     private Object[] toArrayInternal(Object[] a) {
         Object[] x = a;
-        restartFromHead: for (;;) {
+        restart: for (;;) {
             int size = 0;
             for (Node<E> p = first(); p != null;) {
-                E item = p.item;
-                if (item != null) {
+                final E item;
+                if ((item = p.item) != null) {
                     if (x == null)
                         x = new Object[4];
                     else if (size == x.length)
@@ -1251,7 +1254,7 @@
                     x[size++] = item;
                 }
                 if (p == (p = p.next))
-                    continue restartFromHead;
+                    continue restart;
             }
             if (x == null)
                 return new Object[0];
@@ -1395,8 +1398,8 @@
                     nextItem = null;
                     break;
                 }
-                E item = p.item;
-                if (item != null) {
+                final E item;
+                if ((item = p.item) != null) {
                     nextNode = p;
                     nextItem = item;
                     break;
@@ -1426,90 +1429,75 @@
 
     /** Forward iterator */
     private class Itr extends AbstractItr {
+        Itr() {}                        // prevent access constructor creation
         Node<E> startNode() { return first(); }
         Node<E> nextNode(Node<E> p) { return succ(p); }
     }
 
     /** Descending iterator */
     private class DescendingItr extends AbstractItr {
+        DescendingItr() {}              // prevent access constructor creation
         Node<E> startNode() { return last(); }
         Node<E> nextNode(Node<E> p) { return pred(p); }
     }
 
     /** A customized variant of Spliterators.IteratorSpliterator */
-    static final class CLDSpliterator<E> implements Spliterator<E> {
+    final class CLDSpliterator implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
-        final ConcurrentLinkedDeque<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
-        CLDSpliterator(ConcurrentLinkedDeque<E> queue) {
-            this.queue = queue;
-        }
 
         public Spliterator<E> trySplit() {
-            Node<E> p;
-            final ConcurrentLinkedDeque<E> q = this.queue;
-            int b = batch;
-            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
-            if (!exhausted &&
-                ((p = current) != null || (p = q.first()) != null)) {
-                if (p.item == null && p == (p = p.next))
-                    current = p = q.first();
-                if (p != null && p.next != null) {
-                    Object[] a = new Object[n];
-                    int i = 0;
-                    do {
-                        if ((a[i] = p.item) != null)
-                            ++i;
-                        if (p == (p = p.next))
-                            p = q.first();
-                    } while (p != null && i < n);
-                    if ((current = p) == null)
-                        exhausted = true;
-                    if (i > 0) {
-                        batch = i;
-                        return Spliterators.spliterator
-                            (a, 0, i, (Spliterator.ORDERED |
-                                       Spliterator.NONNULL |
-                                       Spliterator.CONCURRENT));
-                    }
+            Node<E> p, q;
+            if ((p = current()) == null || (q = p.next) == null)
+                return null;
+            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+            Object[] a = null;
+            do {
+                final E e;
+                if ((e = p.item) != null) {
+                    if (a == null)
+                        a = new Object[n];
+                    a[i++] = e;
                 }
-            }
-            return null;
+                if (p == (p = q))
+                    p = first();
+            } while (p != null && (q = p.next) != null && i < n);
+            setCurrent(p);
+            return (i == 0) ? null :
+                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+                                                   Spliterator.NONNULL |
+                                                   Spliterator.CONCURRENT));
         }
 
         public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
             Node<E> p;
-            if (action == null) throw new NullPointerException();
-            final ConcurrentLinkedDeque<E> q = this.queue;
-            if (!exhausted &&
-                ((p = current) != null || (p = q.first()) != null)) {
+            if ((p = current()) != null) {
+                current = null;
                 exhausted = true;
                 do {
-                    E e = p.item;
-                    if (p == (p = p.next))
-                        p = q.first();
-                    if (e != null)
+                    final E e;
+                    if ((e = p.item) != null)
                         action.accept(e);
+                    if (p == (p = p.next))
+                        p = first();
                 } while (p != null);
             }
         }
 
         public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
             Node<E> p;
-            if (action == null) throw new NullPointerException();
-            final ConcurrentLinkedDeque<E> q = this.queue;
-            if (!exhausted &&
-                ((p = current) != null || (p = q.first()) != null)) {
+            if ((p = current()) != null) {
                 E e;
                 do {
                     e = p.item;
                     if (p == (p = p.next))
-                        p = q.first();
+                        p = first();
                 } while (e == null && p != null);
-                if ((current = p) == null)
-                    exhausted = true;
+                setCurrent(p);
                 if (e != null) {
                     action.accept(e);
                     return true;
@@ -1518,11 +1506,24 @@
             return false;
         }
 
+        private void setCurrent(Node<E> p) {
+            if ((current = p) == null)
+                exhausted = true;
+        }
+
+        private Node<E> current() {
+            Node<E> p;
+            if ((p = current) == null && !exhausted)
+                setCurrent(p = first());
+            return p;
+        }
+
         public long estimateSize() { return Long.MAX_VALUE; }
 
         public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.NONNULL |
-                Spliterator.CONCURRENT;
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
         }
     }
 
@@ -1543,7 +1544,7 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new CLDSpliterator<E>(this);
+        return new CLDSpliterator();
     }
 
     /**
@@ -1562,8 +1563,8 @@
 
         // Write out all elements in the proper order.
         for (Node<E> p = first(); p != null; p = succ(p)) {
-            E item = p.item;
-            if (item != null)
+            final E item;
+            if ((item = p.item) != null)
                 s.writeObject(item);
         }
 
@@ -1586,43 +1587,91 @@
         Node<E> h = null, t = null;
         for (Object item; (item = s.readObject()) != null; ) {
             @SuppressWarnings("unchecked")
-            Node<E> newNode = new Node<E>((E) item);
+            Node<E> newNode = newNode((E) item);
             if (h == null)
                 h = t = newNode;
             else {
-                t.lazySetNext(newNode);
-                newNode.lazySetPrev(t);
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
                 t = newNode;
             }
         }
         initHeadTail(h, t);
     }
 
-    private boolean casHead(Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
     }
 
-    private boolean casTail(Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(this, TAIL, cmp, val);
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
     }
 
-    // Unsafe mechanics
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
 
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long HEAD;
-    private static final long TAIL;
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        for (Node<E> p = first(), succ; p != null; p = succ) {
+            succ = succ(p);
+            final E item;
+            if ((item = p.item) != null
+                && filter.test(item)
+                && ITEM.compareAndSet(p, item, null)) {
+                unlink(p);
+                removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        E item;
+        for (Node<E> p = first(); p != null; p = succ(p))
+            if ((item = p.item) != null)
+                action.accept(item);
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    private static final VarHandle PREV;
+    private static final VarHandle NEXT;
+    private static final VarHandle ITEM;
     static {
         PREV_TERMINATOR = new Node<Object>();
         PREV_TERMINATOR.next = PREV_TERMINATOR;
         NEXT_TERMINATOR = new Node<Object>();
         NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
         try {
-            HEAD = U.objectFieldOffset
-                (ConcurrentLinkedDeque.class.getDeclaredField("head"));
-            TAIL = U.objectFieldOffset
-                (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentLinkedDeque.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(ConcurrentLinkedDeque.class, "tail",
+                                   Node.class);
+            PREV = l.findVarHandle(Node.class, "prev", Node.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            ITEM = l.findVarHandle(Node.class, "item", Object.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
index 7997c60..eac8ee7 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
@@ -45,10 +47,7 @@
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
 
 /**
  * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
@@ -82,12 +81,12 @@
  * asynchronous nature of these queues, determining the current number
  * of elements requires a traversal of the elements, and so may report
  * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code addAll},
- * {@code removeAll}, {@code retainAll}, {@code containsAll},
- * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
- * to be performed atomically. For example, an iterator operating
- * concurrently with an {@code addAll} operation might view only some
- * of the added elements.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe only some of the added elements.
  *
  * <p>This class and its iterator implement all of the <em>optional</em>
  * methods of the {@link Queue} and {@link Iterator} interfaces.
@@ -99,6 +98,10 @@
  * actions subsequent to the access or removal of that element from
  * the {@code ConcurrentLinkedQueue} in another thread.
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
@@ -110,7 +113,7 @@
     /*
      * This is a modification of the Michael & Scott algorithm,
      * adapted for a garbage-collected environment, with support for
-     * interior node deletion (to support remove(Object)).  For
+     * interior node deletion (to support e.g. remove(Object)).  For
      * explanation, read the paper.
      *
      * Note that like most non-blocking algorithms in this package,
@@ -158,17 +161,17 @@
      * it is possible for tail to lag behind head (why not)?
      *
      * CASing a Node's item reference to null atomically removes the
-     * element from the queue.  Iterators skip over Nodes with null
-     * items.  Prior implementations of this class had a race between
-     * poll() and remove(Object) where the same element would appear
-     * to be successfully removed by two concurrent operations.  The
-     * method remove(Object) also lazily unlinks deleted Nodes, but
-     * this is merely an optimization.
+     * element from the queue, leaving a "dead" node that should later
+     * be unlinked (but unlinking is merely an optimization).
+     * Interior element removal methods (other than Iterator.remove())
+     * keep track of the predecessor node during traversal so that the
+     * node can be CAS-unlinked.  Some traversal methods try to unlink
+     * any deleted nodes encountered during traversal.  See comments
+     * in bulkRemove.
      *
      * When constructing a Node (before enqueuing it) we avoid paying
-     * for a volatile write to item by using Unsafe.putObject instead
-     * of a normal write.  This allows the cost of enqueue to be
-     * "one-and-a-half" CASes.
+     * for a volatile write to item.  This allows the cost of enqueue
+     * to be "one-and-a-half" CASes.
      *
      * Both head and tail may or may not point to a Node with a
      * non-null item.  If the queue is empty, all items must of course
@@ -178,31 +181,33 @@
      * optimization.
      */
 
-    private static class Node<E> {
+    static final class Node<E> {
         volatile E item;
         volatile Node<E> next;
-    }
 
-    /**
-     * Returns a new node holding item.  Uses relaxed write because item
-     * can only be seen after piggy-backing publication via casNext.
-     */
-    static <E> Node<E> newNode(E item) {
-        Node<E> node = new Node<E>();
-        U.putObject(node, ITEM, item);
-        return node;
-    }
+        /**
+         * Constructs a node holding item.  Uses relaxed write because
+         * item can only be seen after piggy-backing publication via CAS.
+         */
+        Node(E item) {
+            ITEM.set(this, item);
+        }
 
-    static <E> boolean casItem(Node<E> node, E cmp, E val) {
-        return U.compareAndSwapObject(node, ITEM, cmp, val);
-    }
+        /** Constructs a dead dummy node. */
+        Node() {}
 
-    static <E> void lazySetNext(Node<E> node, Node<E> val) {
-        U.putOrderedObject(node, NEXT, val);
-    }
+        void appendRelaxed(Node<E> next) {
+            // assert next != null;
+            // assert this.next == null;
+            NEXT.set(this, next);
+        }
 
-    static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(node, NEXT, cmp, val);
+        boolean casItem(E cmp, E val) {
+            // assert item == cmp || item == null;
+            // assert cmp != null;
+            // assert val == null;
+            return ITEM.compareAndSet(this, cmp, val);
+        }
     }
 
     /**
@@ -229,7 +234,7 @@
      * - tail.item may or may not be null.
      * - it is permitted for tail to lag behind head, that is, for tail
      *   to not be reachable from head!
-     * - tail.next may or may not be self-pointing to tail.
+     * - tail.next may or may not be self-linked.
      */
     private transient volatile Node<E> tail;
 
@@ -237,7 +242,7 @@
      * Creates a {@code ConcurrentLinkedQueue} that is initially empty.
      */
     public ConcurrentLinkedQueue() {
-        head = tail = newNode(null);
+        head = tail = new Node<E>();
     }
 
     /**
@@ -252,16 +257,14 @@
     public ConcurrentLinkedQueue(Collection<? extends E> c) {
         Node<E> h = null, t = null;
         for (E e : c) {
-            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
             if (h == null)
                 h = t = newNode;
-            else {
-                lazySetNext(t, newNode);
-                t = newNode;
-            }
+            else
+                t.appendRelaxed(t = newNode);
         }
         if (h == null)
-            h = t = newNode(null);
+            h = t = new Node<E>();
         head = h;
         tail = t;
     }
@@ -286,8 +289,8 @@
      */
     final void updateHead(Node<E> h, Node<E> p) {
         // assert h != null && p != null && (h == p || h.item == null);
-        if (h != p && casHead(h, p))
-            lazySetNext(h, h);
+        if (h != p && HEAD.compareAndSet(this, h, p))
+            NEXT.setRelease(h, h);
     }
 
     /**
@@ -296,8 +299,49 @@
      * stale pointer that is now off the list.
      */
     final Node<E> succ(Node<E> p) {
-        Node<E> next = p.next;
-        return (p == next) ? head : next;
+        if (p == (p = p.next))
+            p = head;
+        return p;
+    }
+
+    /**
+     * Tries to CAS pred.next (or head, if pred is null) from c to p.
+     * Caller must ensure that we're not unlinking the trailing node.
+     */
+    private boolean tryCasSuccessor(Node<E> pred, Node<E> c, Node<E> p) {
+        // assert p != null;
+        // assert c.item == null;
+        // assert c != p;
+        if (pred != null)
+            return NEXT.compareAndSet(pred, c, p);
+        if (HEAD.compareAndSet(this, c, p)) {
+            NEXT.setRelease(c, c);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Collapse dead nodes between pred and q.
+     * @param pred the last known live node, or null if none
+     * @param c the first dead node
+     * @param p the last dead node
+     * @param q p.next: the next live node, or null if at end
+     * @return either old pred or p if pred dead or CAS failed
+     */
+    private Node<E> skipDeadNodes(Node<E> pred, Node<E> c, Node<E> p, Node<E> q) {
+        // assert pred != c;
+        // assert p != q;
+        // assert c.item == null;
+        // assert p.item == null;
+        if (q == null) {
+            // Never unlink trailing node.
+            if (c == p) return pred;
+            q = p;
+        }
+        return (tryCasSuccessor(pred, c, q)
+                && (pred == null || ITEM.get(pred) != null))
+            ? pred : p;
     }
 
     /**
@@ -308,18 +352,18 @@
      * @throws NullPointerException if the specified element is null
      */
     public boolean offer(E e) {
-        final Node<E> newNode = newNode(Objects.requireNonNull(e));
+        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
 
         for (Node<E> t = tail, p = t;;) {
             Node<E> q = p.next;
             if (q == null) {
                 // p is last node
-                if (casNext(p, null, newNode)) {
+                if (NEXT.compareAndSet(p, null, newNode)) {
                     // Successful CAS is the linearization point
                     // for e to become an element of this queue,
                     // and for newNode to become "live".
-                    if (p != t) // hop two nodes at a time
-                        casTail(t, newNode);  // Failure is OK.
+                    if (p != t) // hop two nodes at a time; failure is OK
+                        TAIL.weakCompareAndSet(this, t, newNode);
                     return true;
                 }
                 // Lost CAS race to another thread; re-read next
@@ -337,12 +381,10 @@
     }
 
     public E poll() {
-        restartFromHead:
-        for (;;) {
-            for (Node<E> h = head, p = h, q;;) {
-                E item = p.item;
-
-                if (item != null && casItem(p, item, null)) {
+        restartFromHead: for (;;) {
+            for (Node<E> h = head, p = h, q;; p = q) {
+                final E item;
+                if ((item = p.item) != null && p.casItem(item, null)) {
                     // Successful CAS is the linearization point
                     // for item to be removed from this queue.
                     if (p != h) // hop two nodes at a time
@@ -355,25 +397,21 @@
                 }
                 else if (p == q)
                     continue restartFromHead;
-                else
-                    p = q;
             }
         }
     }
 
     public E peek() {
-        restartFromHead:
-        for (;;) {
-            for (Node<E> h = head, p = h, q;;) {
-                E item = p.item;
-                if (item != null || (q = p.next) == null) {
+        restartFromHead: for (;;) {
+            for (Node<E> h = head, p = h, q;; p = q) {
+                final E item;
+                if ((item = p.item) != null
+                    || (q = p.next) == null) {
                     updateHead(h, p);
                     return item;
                 }
                 else if (p == q)
                     continue restartFromHead;
-                else
-                    p = q;
             }
         }
     }
@@ -387,9 +425,8 @@
      * of losing a race to a concurrent poll().
      */
     Node<E> first() {
-        restartFromHead:
-        for (;;) {
-            for (Node<E> h = head, p = h, q;;) {
+        restartFromHead: for (;;) {
+            for (Node<E> h = head, p = h, q;; p = q) {
                 boolean hasItem = (p.item != null);
                 if (hasItem || (q = p.next) == null) {
                     updateHead(h, p);
@@ -397,8 +434,6 @@
                 }
                 else if (p == q)
                     continue restartFromHead;
-                else
-                    p = q;
             }
         }
     }
@@ -451,14 +486,25 @@
      * @return {@code true} if this queue contains the specified element
      */
     public boolean contains(Object o) {
-        if (o != null) {
-            for (Node<E> p = first(); p != null; p = succ(p)) {
-                E item = p.item;
-                if (item != null && o.equals(item))
-                    return true;
+        if (o == null) return false;
+        restartFromHead: for (;;) {
+            for (Node<E> p = head, pred = null; p != null; ) {
+                Node<E> q = p.next;
+                final E item;
+                if ((item = p.item) != null) {
+                    if (o.equals(item))
+                        return true;
+                    pred = p; p = q; continue;
+                }
+                for (Node<E> c = p;; q = p.next) {
+                    if (q == null || q.item != null) {
+                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                    }
+                    if (p == (p = q)) continue restartFromHead;
+                }
             }
+            return false;
         }
-        return false;
     }
 
     /**
@@ -473,27 +519,27 @@
      * @return {@code true} if this queue changed as a result of the call
      */
     public boolean remove(Object o) {
-        if (o != null) {
-            Node<E> next, pred = null;
-            for (Node<E> p = first(); p != null; pred = p, p = next) {
-                boolean removed = false;
-                E item = p.item;
-                if (item != null) {
-                    if (!o.equals(item)) {
-                        next = succ(p);
-                        continue;
+        if (o == null) return false;
+        restartFromHead: for (;;) {
+            for (Node<E> p = head, pred = null; p != null; ) {
+                Node<E> q = p.next;
+                final E item;
+                if ((item = p.item) != null) {
+                    if (o.equals(item) && p.casItem(item, null)) {
+                        skipDeadNodes(pred, p, p, q);
+                        return true;
                     }
-                    removed = casItem(p, item, null);
+                    pred = p; p = q; continue;
                 }
-
-                next = succ(p);
-                if (pred != null && next != null) // unlink
-                    casNext(pred, p, next);
-                if (removed)
-                    return true;
+                for (Node<E> c = p;; q = p.next) {
+                    if (q == null || q.item != null) {
+                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                    }
+                    if (p == (p = q)) continue restartFromHead;
+                }
             }
+            return false;
         }
-        return false;
     }
 
     /**
@@ -516,13 +562,11 @@
         // Copy c into a private chain of Nodes
         Node<E> beginningOfTheEnd = null, last = null;
         for (E e : c) {
-            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
             if (beginningOfTheEnd == null)
                 beginningOfTheEnd = last = newNode;
-            else {
-                lazySetNext(last, newNode);
-                last = newNode;
-            }
+            else
+                last.appendRelaxed(last = newNode);
         }
         if (beginningOfTheEnd == null)
             return false;
@@ -532,15 +576,15 @@
             Node<E> q = p.next;
             if (q == null) {
                 // p is last node
-                if (casNext(p, null, beginningOfTheEnd)) {
+                if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
                     // Successful CAS is the linearization point
                     // for all elements to be added to this queue.
-                    if (!casTail(t, last)) {
+                    if (!TAIL.weakCompareAndSet(this, t, last)) {
                         // Try a little harder to update tail,
                         // since we may be adding many elements.
                         t = tail;
                         if (last.next == null)
-                            casTail(t, last);
+                            TAIL.weakCompareAndSet(this, t, last);
                     }
                     return true;
                 }
@@ -564,8 +608,8 @@
             int charLength = 0;
             int size = 0;
             for (Node<E> p = first(); p != null;) {
-                E item = p.item;
-                if (item != null) {
+                final E item;
+                if ((item = p.item) != null) {
                     if (a == null)
                         a = new String[4];
                     else if (size == a.length)
@@ -590,8 +634,8 @@
         restartFromHead: for (;;) {
             int size = 0;
             for (Node<E> p = first(); p != null;) {
-                E item = p.item;
-                if (item != null) {
+                final E item;
+                if ((item = p.item) != null) {
                     if (x == null)
                         x = new Object[4];
                     else if (size == x.length)
@@ -668,7 +712,7 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        if (a == null) throw new NullPointerException();
+        Objects.requireNonNull(a);
         return (T[]) toArrayInternal(a);
     }
 
@@ -708,7 +752,7 @@
             restartFromHead: for (;;) {
                 Node<E> h, p, q;
                 for (p = h = head;; p = q) {
-                    E item;
+                    final E item;
                     if ((item = p.item) != null) {
                         nextNode = p;
                         nextItem = item;
@@ -744,10 +788,12 @@
                 }
                 // unlink deleted nodes
                 if ((q = succ(p)) != null)
-                    casNext(pred, p, q);
+                    NEXT.compareAndSet(pred, p, q);
             }
         }
 
+        // Default implementation of forEachRemaining is "good enough".
+
         public void remove() {
             Node<E> l = lastRet;
             if (l == null) throw new IllegalStateException();
@@ -773,8 +819,8 @@
 
         // Write out all elements in the proper order.
         for (Node<E> p = first(); p != null; p = succ(p)) {
-            Object item = p.item;
-            if (item != null)
+            final E item;
+            if ((item = p.item) != null)
                 s.writeObject(item);
         }
 
@@ -797,91 +843,69 @@
         Node<E> h = null, t = null;
         for (Object item; (item = s.readObject()) != null; ) {
             @SuppressWarnings("unchecked")
-            Node<E> newNode = newNode((E) item);
+            Node<E> newNode = new Node<E>((E) item);
             if (h == null)
                 h = t = newNode;
-            else {
-                lazySetNext(t, newNode);
-                t = newNode;
-            }
+            else
+                t.appendRelaxed(t = newNode);
         }
         if (h == null)
-            h = t = newNode(null);
+            h = t = new Node<E>();
         head = h;
         tail = t;
     }
 
     /** A customized variant of Spliterators.IteratorSpliterator */
-    static final class CLQSpliterator<E> implements Spliterator<E> {
+    final class CLQSpliterator implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
-        final ConcurrentLinkedQueue<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
-        CLQSpliterator(ConcurrentLinkedQueue<E> queue) {
-            this.queue = queue;
-        }
 
         public Spliterator<E> trySplit() {
-            Node<E> p;
-            final ConcurrentLinkedQueue<E> q = this.queue;
-            int b = batch;
-            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
-            if (!exhausted &&
-                ((p = current) != null || (p = q.first()) != null) &&
-                p.next != null) {
-                Object[] a = new Object[n];
-                int i = 0;
-                do {
-                    if ((a[i] = p.item) != null)
-                        ++i;
-                    if (p == (p = p.next))
-                        p = q.first();
-                } while (p != null && i < n);
-                if ((current = p) == null)
-                    exhausted = true;
-                if (i > 0) {
-                    batch = i;
-                    return Spliterators.spliterator
-                        (a, 0, i, (Spliterator.ORDERED |
-                                   Spliterator.NONNULL |
-                                   Spliterator.CONCURRENT));
+            Node<E> p, q;
+            if ((p = current()) == null || (q = p.next) == null)
+                return null;
+            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+            Object[] a = null;
+            do {
+                final E e;
+                if ((e = p.item) != null) {
+                    if (a == null)
+                        a = new Object[n];
+                    a[i++] = e;
                 }
-            }
-            return null;
+                if (p == (p = q))
+                    p = first();
+            } while (p != null && (q = p.next) != null && i < n);
+            setCurrent(p);
+            return (i == 0) ? null :
+                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+                                                   Spliterator.NONNULL |
+                                                   Spliterator.CONCURRENT));
         }
 
         public void forEachRemaining(Consumer<? super E> action) {
-            Node<E> p;
-            if (action == null) throw new NullPointerException();
-            final ConcurrentLinkedQueue<E> q = this.queue;
-            if (!exhausted &&
-                ((p = current) != null || (p = q.first()) != null)) {
+            Objects.requireNonNull(action);
+            final Node<E> p;
+            if ((p = current()) != null) {
+                current = null;
                 exhausted = true;
-                do {
-                    E e = p.item;
-                    if (p == (p = p.next))
-                        p = q.first();
-                    if (e != null)
-                        action.accept(e);
-                } while (p != null);
+                forEachFrom(action, p);
             }
         }
 
         public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
             Node<E> p;
-            if (action == null) throw new NullPointerException();
-            final ConcurrentLinkedQueue<E> q = this.queue;
-            if (!exhausted &&
-                ((p = current) != null || (p = q.first()) != null)) {
+            if ((p = current()) != null) {
                 E e;
                 do {
                     e = p.item;
                     if (p == (p = p.next))
-                        p = q.first();
+                        p = first();
                 } while (e == null && p != null);
-                if ((current = p) == null)
-                    exhausted = true;
+                setCurrent(p);
                 if (e != null) {
                     action.accept(e);
                     return true;
@@ -890,11 +914,24 @@
             return false;
         }
 
+        private void setCurrent(Node<E> p) {
+            if ((current = p) == null)
+                exhausted = true;
+        }
+
+        private Node<E> current() {
+            Node<E> p;
+            if ((p = current) == null && !exhausted)
+                setCurrent(p = first());
+            return p;
+        }
+
         public long estimateSize() { return Long.MAX_VALUE; }
 
         public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.NONNULL |
-                Spliterator.CONCURRENT;
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
         }
     }
 
@@ -916,36 +953,123 @@
      */
     @Override
     public Spliterator<E> spliterator() {
-        return new CLQSpliterator<E>(this);
+        return new CLQSpliterator();
     }
 
-    private boolean casTail(Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(this, TAIL, cmp, val);
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
     }
 
-    private boolean casHead(Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
     }
 
-    // Unsafe mechanics
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
 
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long HEAD;
-    private static final long TAIL;
-    private static final long ITEM;
-    private static final long NEXT;
+    public void clear() {
+        bulkRemove(e -> true);
+    }
+
+    /**
+     * Tolerate this many consecutive dead nodes before CAS-collapsing.
+     * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element.
+     */
+    private static final int MAX_HOPS = 8;
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        restartFromHead: for (;;) {
+            int hops = MAX_HOPS;
+            // c will be CASed to collapse intervening dead nodes between
+            // pred (or head if null) and p.
+            for (Node<E> p = head, c = p, pred = null, q; p != null; p = q) {
+                q = p.next;
+                final E item; boolean pAlive;
+                if (pAlive = ((item = p.item) != null)) {
+                    if (filter.test(item)) {
+                        if (p.casItem(item, null))
+                            removed = true;
+                        pAlive = false;
+                    }
+                }
+                if (pAlive || q == null || --hops == 0) {
+                    // p might already be self-linked here, but if so:
+                    // - CASing head will surely fail
+                    // - CASing pred's next will be useless but harmless.
+                    if ((c != p && !tryCasSuccessor(pred, c, c = p))
+                        || pAlive) {
+                        // if CAS failed or alive, abandon old pred
+                        hops = MAX_HOPS;
+                        pred = p;
+                        c = q;
+                    }
+                } else if (p == q)
+                    continue restartFromHead;
+            }
+            return removed;
+        }
+    }
+
+    /**
+     * Runs action on each element found during a traversal starting at p.
+     * If p is null, the action is not run.
+     */
+    void forEachFrom(Consumer<? super E> action, Node<E> p) {
+        for (Node<E> pred = null; p != null; ) {
+            Node<E> q = p.next;
+            final E item;
+            if ((item = p.item) != null) {
+                action.accept(item);
+                pred = p; p = q; continue;
+            }
+            for (Node<E> c = p;; q = p.next) {
+                if (q == null || q.item != null) {
+                    pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                }
+                if (p == (p = q)) { pred = null; p = head; break; }
+            }
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        forEachFrom(action, head);
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    static final VarHandle ITEM;
+    static final VarHandle NEXT;
     static {
         try {
-            HEAD = U.objectFieldOffset
-                (ConcurrentLinkedQueue.class.getDeclaredField("head"));
-            TAIL = U.objectFieldOffset
-                (ConcurrentLinkedQueue.class.getDeclaredField("tail"));
-            ITEM = U.objectFieldOffset
-                (Node.class.getDeclaredField("item"));
-            NEXT = U.objectFieldOffset
-                (Node.class.getDeclaredField("next"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentLinkedQueue.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(ConcurrentLinkedQueue.class, "tail",
+                                   Node.class);
+            ITEM = l.findVarHandle(Node.class, "item", Object.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
index 69dae6f..2037e31 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
@@ -41,14 +41,8 @@
 import java.util.function.BiFunction;
 import java.util.function.Function;
 
-// BEGIN android-note
-// removed link to collections framework docs
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
 /**
- * A {@link java.util.Map} providing thread safety and atomicity
- * guarantees.
+ * A {@link Map} providing thread safety and atomicity guarantees.
  *
  * <p>To maintain the specified guarantees, default implementations of
  * methods including {@link #putIfAbsent} inherited from {@link Map}
@@ -65,6 +59,10 @@
  * actions subsequent to the access or removal of that object from
  * the {@code ConcurrentMap} in another thread.
  *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
@@ -182,10 +180,10 @@
      *         is not supported by this map
      * @throws ClassCastException if the key or value is of an inappropriate
      *         type for this map
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified key or value is null,
      *         and this map does not permit null keys or values
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object key, Object value);
 
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
index 94a90cd..1666c8b 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
@@ -38,14 +38,14 @@
 import java.util.NavigableMap;
 import java.util.NavigableSet;
 
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
 /**
  * A {@link ConcurrentMap} supporting {@link NavigableMap} operations,
  * and recursively so for its navigable sub-maps.
  *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
index 583244b..db14d4b 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.io.Serializable;
 import java.util.AbstractCollection;
 import java.util.AbstractMap;
@@ -46,7 +48,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.NavigableMap;
 import java.util.NavigableSet;
 import java.util.NoSuchElementException;
 import java.util.Set;
@@ -57,10 +58,7 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.concurrent.atomic.LongAdder;
 
 /**
  * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
@@ -89,12 +87,7 @@
  * associated map using {@code put}, {@code putIfAbsent}, or
  * {@code replace}, depending on exactly which effect you need.)
  *
- * <p>Beware that, unlike in most collections, the {@code size}
- * method is <em>not</em> a constant-time operation. Because of the
- * asynchronous nature of these maps, determining the current number
- * of elements requires a traversal of the elements, and so may report
- * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code putAll}, {@code equals},
+ * <p>Beware that bulk operations {@code putAll}, {@code equals},
  * {@code toArray}, {@code containsValue}, and {@code clear} are
  * <em>not</em> guaranteed to be performed atomically. For example, an
  * iterator operating concurrently with a {@code putAll} operation
@@ -107,6 +100,10 @@
  * null return values cannot be reliably distinguished from the absence of
  * elements.
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
@@ -157,42 +154,35 @@
      * be slow and space-intensive using AtomicMarkedReference), nodes
      * use direct CAS'able next pointers.  On deletion, instead of
      * marking a pointer, they splice in another node that can be
-     * thought of as standing for a marked pointer (indicating this by
-     * using otherwise impossible field values).  Using plain nodes
-     * acts roughly like "boxed" implementations of marked pointers,
-     * but uses new nodes only when nodes are deleted, not for every
-     * link.  This requires less space and supports faster
-     * traversal. Even if marked references were better supported by
-     * JVMs, traversal using this technique might still be faster
-     * because any search need only read ahead one more node than
-     * otherwise required (to check for trailing marker) rather than
-     * unmasking mark bits or whatever on each read.
+     * thought of as standing for a marked pointer (see method
+     * unlinkNode).  Using plain nodes acts roughly like "boxed"
+     * implementations of marked pointers, but uses new nodes only
+     * when nodes are deleted, not for every link.  This requires less
+     * space and supports faster traversal. Even if marked references
+     * were better supported by JVMs, traversal using this technique
+     * might still be faster because any search need only read ahead
+     * one more node than otherwise required (to check for trailing
+     * marker) rather than unmasking mark bits or whatever on each
+     * read.
      *
      * This approach maintains the essential property needed in the HM
      * algorithm of changing the next-pointer of a deleted node so
      * that any other CAS of it will fail, but implements the idea by
-     * changing the pointer to point to a different node, not by
-     * marking it.  While it would be possible to further squeeze
-     * space by defining marker nodes not to have key/value fields, it
-     * isn't worth the extra type-testing overhead.  The deletion
-     * markers are rarely encountered during traversal and are
-     * normally quickly garbage collected. (Note that this technique
-     * would not work well in systems without garbage collection.)
+     * changing the pointer to point to a different node (with
+     * otherwise illegal null fields), not by marking it.  While it
+     * would be possible to further squeeze space by defining marker
+     * nodes not to have key/value fields, it isn't worth the extra
+     * type-testing overhead.  The deletion markers are rarely
+     * encountered during traversal, are easily detected via null
+     * checks that are needed anyway, and are normally quickly garbage
+     * collected. (Note that this technique would not work well in
+     * systems without garbage collection.)
      *
      * In addition to using deletion markers, the lists also use
      * nullness of value fields to indicate deletion, in a style
      * similar to typical lazy-deletion schemes.  If a node's value is
      * null, then it is considered logically deleted and ignored even
-     * though it is still reachable. This maintains proper control of
-     * concurrent replace vs delete operations -- an attempted replace
-     * must fail if a delete beat it by nulling field, and a delete
-     * must return the last non-null value held in the field. (Note:
-     * Null, rather than some special marker, is used for value fields
-     * here because it just so happens to mesh with the Map API
-     * requirement that method get returns null if there is no
-     * mapping, which allows nodes to remain concurrently readable
-     * even when deleted. Using any other marker value here would be
-     * messy at best.)
+     * though it is still reachable.
      *
      * Here's the sequence of events for a deletion of node n with
      * predecessor b and successor f, initially:
@@ -202,9 +192,8 @@
      *        +------+       +------+      +------+
      *
      * 1. CAS n's value field from non-null to null.
-     *    From this point on, no public operations encountering
-     *    the node consider this mapping to exist. However, other
-     *    ongoing insertions and deletions might still modify
+     *    Traversals encountering a node with null value ignore it.
+     *    However, ongoing insertions and deletions might still modify
      *    n's next pointer.
      *
      * 2. CAS n's next pointer to point to a new marker node.
@@ -227,12 +216,7 @@
      * thread noticed during a traversal a node with null value and
      * helped out by marking and/or unlinking.  This helping-out
      * ensures that no thread can become stuck waiting for progress of
-     * the deleting thread.  The use of marker nodes slightly
-     * complicates helping-out code because traversals must track
-     * consistent reads of up to four nodes (b, n, marker, f), not
-     * just (b, n, f), although the next field of a marker is
-     * immutable, and once a next field is CAS'ed to point to a
-     * marker, it never again changes, so this requires less care.
+     * the deleting thread.
      *
      * Skip lists add indexing to this scheme, so that the base-level
      * traversals start close to the locations being found, inserted
@@ -242,113 +226,101 @@
      * b) that are not (structurally) deleted, otherwise retrying
      * after processing the deletion.
      *
-     * Index levels are maintained as lists with volatile next fields,
-     * using CAS to link and unlink.  Races are allowed in index-list
-     * operations that can (rarely) fail to link in a new index node
-     * or delete one. (We can't do this of course for data nodes.)
-     * However, even when this happens, the index lists remain sorted,
-     * so correctly serve as indices.  This can impact performance,
-     * but since skip lists are probabilistic anyway, the net result
-     * is that under contention, the effective "p" value may be lower
-     * than its nominal value. And race windows are kept small enough
-     * that in practice these failures are rare, even under a lot of
-     * contention.
+     * Index levels are maintained using CAS to link and unlink
+     * successors ("right" fields).  Races are allowed in index-list
+     * operations that can (rarely) fail to link in a new index node.
+     * (We can't do this of course for data nodes.)  However, even
+     * when this happens, the index lists correctly guide search.
+     * This can impact performance, but since skip lists are
+     * probabilistic anyway, the net result is that under contention,
+     * the effective "p" value may be lower than its nominal value.
      *
-     * The fact that retries (for both base and index lists) are
-     * relatively cheap due to indexing allows some minor
-     * simplifications of retry logic. Traversal restarts are
-     * performed after most "helping-out" CASes. This isn't always
-     * strictly necessary, but the implicit backoffs tend to help
-     * reduce other downstream failed CAS's enough to outweigh restart
-     * cost.  This worsens the worst case, but seems to improve even
-     * highly contended cases.
-     *
-     * Unlike most skip-list implementations, index insertion and
-     * deletion here require a separate traversal pass occurring after
-     * the base-level action, to add or remove index nodes.  This adds
-     * to single-threaded overhead, but improves contended
-     * multithreaded performance by narrowing interference windows,
-     * and allows deletion to ensure that all index nodes will be made
-     * unreachable upon return from a public remove operation, thus
-     * avoiding unwanted garbage retention. This is more important
-     * here than in some other data structures because we cannot null
-     * out node fields referencing user keys since they might still be
-     * read by other ongoing traversals.
+     * Index insertion and deletion sometimes require a separate
+     * traversal pass occurring after the base-level action, to add or
+     * remove index nodes.  This adds to single-threaded overhead, but
+     * improves contended multithreaded performance by narrowing
+     * interference windows, and allows deletion to ensure that all
+     * index nodes will be made unreachable upon return from a public
+     * remove operation, thus avoiding unwanted garbage retention.
      *
      * Indexing uses skip list parameters that maintain good search
      * performance while using sparser-than-usual indices: The
-     * hardwired parameters k=1, p=0.5 (see method doPut) mean
-     * that about one-quarter of the nodes have indices. Of those that
-     * do, half have one level, a quarter have two, and so on (see
-     * Pugh's Skip List Cookbook, sec 3.4).  The expected total space
-     * requirement for a map is slightly less than for the current
-     * implementation of java.util.TreeMap.
+     * hardwired parameters k=1, p=0.5 (see method doPut) mean that
+     * about one-quarter of the nodes have indices. Of those that do,
+     * half have one level, a quarter have two, and so on (see Pugh's
+     * Skip List Cookbook, sec 3.4), up to a maximum of 62 levels
+     * (appropriate for up to 2^63 elements).  The expected total
+     * space requirement for a map is slightly less than for the
+     * current implementation of java.util.TreeMap.
      *
      * Changing the level of the index (i.e, the height of the
-     * tree-like structure) also uses CAS. The head index has initial
-     * level/height of one. Creation of an index with height greater
-     * than the current level adds a level to the head index by
-     * CAS'ing on a new top-most head. To maintain good performance
-     * after a lot of removals, deletion methods heuristically try to
-     * reduce the height if the topmost levels appear to be empty.
-     * This may encounter races in which it possible (but rare) to
-     * reduce and "lose" a level just as it is about to contain an
-     * index (that will then never be encountered). This does no
-     * structural harm, and in practice appears to be a better option
-     * than allowing unrestrained growth of levels.
+     * tree-like structure) also uses CAS.  Creation of an index with
+     * height greater than the current level adds a level to the head
+     * index by CAS'ing on a new top-most head. To maintain good
+     * performance after a lot of removals, deletion methods
+     * heuristically try to reduce the height if the topmost levels
+     * appear to be empty.  This may encounter races in which it is
+     * possible (but rare) to reduce and "lose" a level just as it is
+     * about to contain an index (that will then never be
+     * encountered). This does no structural harm, and in practice
+     * appears to be a better option than allowing unrestrained growth
+     * of levels.
      *
-     * The code for all this is more verbose than you'd like. Most
-     * operations entail locating an element (or position to insert an
-     * element). The code to do this can't be nicely factored out
-     * because subsequent uses require a snapshot of predecessor
-     * and/or successor and/or value fields which can't be returned
-     * all at once, at least not without creating yet another object
-     * to hold them -- creating such little objects is an especially
-     * bad idea for basic internal search operations because it adds
-     * to GC overhead.  (This is one of the few times I've wished Java
-     * had macros.) Instead, some traversal code is interleaved within
-     * insertion and removal operations.  The control logic to handle
-     * all the retry conditions is sometimes twisty. Most search is
-     * broken into 2 parts. findPredecessor() searches index nodes
-     * only, returning a base-level predecessor of the key. findNode()
-     * finishes out the base-level search. Even with this factoring,
-     * there is a fair amount of near-duplication of code to handle
-     * variants.
+     * This class provides concurrent-reader-style memory consistency,
+     * ensuring that read-only methods report status and/or values no
+     * staler than those holding at method entry. This is done by
+     * performing all publication and structural updates using
+     * (volatile) CAS, placing an acquireFence in a few access
+     * methods, and ensuring that linked objects are transitively
+     * acquired via dependent reads (normally once) unless performing
+     * a volatile-mode CAS operation (that also acts as an acquire and
+     * release).  This form of fence-hoisting is similar to RCU and
+     * related techniques (see McKenney's online book
+     * https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html)
+     * It minimizes overhead that may otherwise occur when using so
+     * many volatile-mode reads. Using explicit acquireFences is
+     * logistically easier than targeting particular fields to be read
+     * in acquire mode: fences are just hoisted up as far as possible,
+     * to the entry points or loop headers of a few methods. A
+     * potential disadvantage is that these few remaining fences are
+     * not easily optimized away by compilers under exclusively
+     * single-thread use.  It requires some care to avoid volatile
+     * mode reads of other fields. (Note that the memory semantics of
+     * a reference dependently read in plain mode exactly once are
+     * equivalent to those for atomic opaque mode.)  Iterators and
+     * other traversals encounter each node and value exactly once.
+     * Other operations locate an element (or position to insert an
+     * element) via a sequence of dereferences. This search is broken
+     * into two parts. Method findPredecessor (and its specialized
+     * embeddings) searches index nodes only, returning a base-level
+     * predecessor of the key. Callers carry out the base-level
+     * search, restarting if encountering a marker preventing link
+     * modification.  In some cases, it is possible to encounter a
+     * node multiple times while descending levels. For mutative
+     * operations, the reported value is validated using CAS (else
+     * retrying), preserving linearizability with respect to each
+     * other. Others may return any (non-null) value holding in the
+     * course of the method call.  (Search-based methods also include
+     * some useless-looking explicit null checks designed to allow
+     * more fields to be nulled out upon removal, to reduce floating
+     * garbage, but which is not currently done, pending discovery of
+     * a way to do this with less impact on other operations.)
      *
      * To produce random values without interference across threads,
      * we use within-JDK thread local random support (via the
      * "secondary seed", to avoid interference with user-level
      * ThreadLocalRandom.)
      *
-     * A previous version of this class wrapped non-comparable keys
-     * with their comparators to emulate Comparables when using
-     * comparators vs Comparables.  However, JVMs now appear to better
-     * handle infusing comparator-vs-comparable choice into search
-     * loops. Static method cpr(comparator, x, y) is used for all
-     * comparisons, which works well as long as the comparator
-     * argument is set up outside of loops (thus sometimes passed as
-     * an argument to internal methods) to avoid field re-reads.
-     *
      * For explanation of algorithms sharing at least a couple of
      * features with this one, see Mikhail Fomitchev's thesis
      * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
      * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
      * thesis (http://www.cs.chalmers.se/~phs/).
      *
-     * Given the use of tree-like index nodes, you might wonder why
-     * this doesn't use some kind of search tree instead, which would
-     * support somewhat faster search operations. The reason is that
-     * there are no known efficient lock-free insertion and deletion
-     * algorithms for search trees. The immutability of the "down"
-     * links of index nodes (as opposed to mutable "left" fields in
-     * true trees) makes this tractable using only CAS operations.
-     *
      * Notation guide for local variables
-     * Node:         b, n, f    for  predecessor, node, successor
+     * Node:         b, n, f, p for  predecessor, node, successor, aux
      * Index:        q, r, d    for index node, right, down.
-     *               t          for another index node
      * Head:         h
-     * Levels:       j
      * Keys:         k, key
      * Values:       v, value
      * Comparisons:  c
@@ -357,16 +329,6 @@
     private static final long serialVersionUID = -8627078645895051609L;
 
     /**
-     * Special value used to identify base-level header.
-     */
-    static final Object BASE_HEADER = new Object();
-
-    /**
-     * The topmost head index of the skiplist.
-     */
-    private transient volatile HeadIndex<K,V> head;
-
-    /**
      * The comparator used to maintain order in this map, or null if
      * using natural ordering.  (Non-private to simplify access in
      * nested classes.)
@@ -374,316 +336,152 @@
      */
     final Comparator<? super K> comparator;
 
+    /** Lazily initialized topmost index of the skiplist. */
+    private transient Index<K,V> head;
+    /** Lazily initialized element count */
+    private transient LongAdder adder;
     /** Lazily initialized key set */
     private transient KeySet<K,V> keySet;
-    /** Lazily initialized entry set */
-    private transient EntrySet<K,V> entrySet;
     /** Lazily initialized values collection */
     private transient Values<K,V> values;
-    /** Lazily initialized descending key set */
-    private transient ConcurrentNavigableMap<K,V> descendingMap;
-
-    /**
-     * Initializes or resets state. Needed by constructors, clone,
-     * clear, readObject. and ConcurrentSkipListSet.clone.
-     * (Note that comparator must be separately initialized.)
-     */
-    private void initialize() {
-        keySet = null;
-        entrySet = null;
-        values = null;
-        descendingMap = null;
-        head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
-                                  null, null, 1);
-    }
-
-    /**
-     * compareAndSet head node.
-     */
-    private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
-        return U.compareAndSwapObject(this, HEAD, cmp, val);
-    }
-
-    /* ---------------- Nodes -------------- */
+    /** Lazily initialized entry set */
+    private transient EntrySet<K,V> entrySet;
+    /** Lazily initialized descending map */
+    private transient SubMap<K,V> descendingMap;
 
     /**
      * Nodes hold keys and values, and are singly linked in sorted
      * order, possibly with some intervening marker nodes. The list is
-     * headed by a dummy node accessible as head.node. The value field
-     * is declared only as Object because it takes special non-V
-     * values for marker and header nodes.
+     * headed by a header node accessible as head.node. Headers and
+     * marker nodes have null keys. The val field (but currently not
+     * the key field) is nulled out upon deletion.
      */
     static final class Node<K,V> {
-        final K key;
-        volatile Object value;
-        volatile Node<K,V> next;
-
-        /**
-         * Creates a new regular node.
-         */
-        Node(K key, Object value, Node<K,V> next) {
+        final K key; // currently, never detached
+        V val;
+        Node<K,V> next;
+        Node(K key, V value, Node<K,V> next) {
             this.key = key;
-            this.value = value;
+            this.val = value;
             this.next = next;
         }
-
-        /**
-         * Creates a new marker node. A marker is distinguished by
-         * having its value field point to itself.  Marker nodes also
-         * have null keys, a fact that is exploited in a few places,
-         * but this doesn't distinguish markers from the base-level
-         * header node (head.node), which also has a null key.
-         */
-        Node(Node<K,V> next) {
-            this.key = null;
-            this.value = this;
-            this.next = next;
-        }
-
-        /**
-         * compareAndSet value field.
-         */
-        boolean casValue(Object cmp, Object val) {
-            return U.compareAndSwapObject(this, VALUE, cmp, val);
-        }
-
-        /**
-         * compareAndSet next field.
-         */
-        boolean casNext(Node<K,V> cmp, Node<K,V> val) {
-            return U.compareAndSwapObject(this, NEXT, cmp, val);
-        }
-
-        /**
-         * Returns true if this node is a marker. This method isn't
-         * actually called in any current code checking for markers
-         * because callers will have already read value field and need
-         * to use that read (not another done here) and so directly
-         * test if value points to node.
-         *
-         * @return true if this node is a marker node
-         */
-        boolean isMarker() {
-            return value == this;
-        }
-
-        /**
-         * Returns true if this node is the header of base-level list.
-         * @return true if this node is header node
-         */
-        boolean isBaseHeader() {
-            return value == BASE_HEADER;
-        }
-
-        /**
-         * Tries to append a deletion marker to this node.
-         * @param f the assumed current successor of this node
-         * @return true if successful
-         */
-        boolean appendMarker(Node<K,V> f) {
-            return casNext(f, new Node<K,V>(f));
-        }
-
-        /**
-         * Helps out a deletion by appending marker or unlinking from
-         * predecessor. This is called during traversals when value
-         * field seen to be null.
-         * @param b predecessor
-         * @param f successor
-         */
-        void helpDelete(Node<K,V> b, Node<K,V> f) {
-            /*
-             * Rechecking links and then doing only one of the
-             * help-out stages per call tends to minimize CAS
-             * interference among helping threads.
-             */
-            if (f == next && this == b.next) {
-                if (f == null || f.value != f) // not already marked
-                    casNext(f, new Node<K,V>(f));
-                else
-                    b.casNext(this, f.next);
-            }
-        }
-
-        /**
-         * Returns value if this node contains a valid key-value pair,
-         * else null.
-         * @return this node's value if it isn't a marker or header or
-         * is deleted, else null
-         */
-        V getValidValue() {
-            Object v = value;
-            if (v == this || v == BASE_HEADER)
-                return null;
-            @SuppressWarnings("unchecked") V vv = (V)v;
-            return vv;
-        }
-
-        /**
-         * Creates and returns a new SimpleImmutableEntry holding current
-         * mapping if this node holds a valid value, else null.
-         * @return new entry or null
-         */
-        AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
-            Object v = value;
-            if (v == null || v == this || v == BASE_HEADER)
-                return null;
-            @SuppressWarnings("unchecked") V vv = (V)v;
-            return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
-        }
-
-        // Unsafe mechanics
-
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-        private static final long VALUE;
-        private static final long NEXT;
-
-        static {
-            try {
-                VALUE = U.objectFieldOffset
-                    (Node.class.getDeclaredField("value"));
-                NEXT = U.objectFieldOffset
-                    (Node.class.getDeclaredField("next"));
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-        }
     }
 
-    /* ---------------- Indexing -------------- */
-
     /**
-     * Index nodes represent the levels of the skip list.  Note that
-     * even though both Nodes and Indexes have forward-pointing
-     * fields, they have different types and are handled in different
-     * ways, that can't nicely be captured by placing field in a
-     * shared abstract class.
+     * Index nodes represent the levels of the skip list.
      */
-    static class Index<K,V> {
-        final Node<K,V> node;
+    static final class Index<K,V> {
+        final Node<K,V> node;  // currently, never detached
         final Index<K,V> down;
-        volatile Index<K,V> right;
-
-        /**
-         * Creates index node with given values.
-         */
+        Index<K,V> right;
         Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
             this.node = node;
             this.down = down;
             this.right = right;
         }
-
-        /**
-         * compareAndSet right field.
-         */
-        final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
-            return U.compareAndSwapObject(this, RIGHT, cmp, val);
-        }
-
-        /**
-         * Returns true if the node this indexes has been deleted.
-         * @return true if indexed node is known to be deleted
-         */
-        final boolean indexesDeletedNode() {
-            return node.value == null;
-        }
-
-        /**
-         * Tries to CAS newSucc as successor.  To minimize races with
-         * unlink that may lose this index node, if the node being
-         * indexed is known to be deleted, it doesn't try to link in.
-         * @param succ the expected current successor
-         * @param newSucc the new successor
-         * @return true if successful
-         */
-        final boolean link(Index<K,V> succ, Index<K,V> newSucc) {
-            Node<K,V> n = node;
-            newSucc.right = succ;
-            return n.value != null && casRight(succ, newSucc);
-        }
-
-        /**
-         * Tries to CAS right field to skip over apparent successor
-         * succ.  Fails (forcing a retraversal by caller) if this node
-         * is known to be deleted.
-         * @param succ the expected current successor
-         * @return true if successful
-         */
-        final boolean unlink(Index<K,V> succ) {
-            return node.value != null && casRight(succ, succ.right);
-        }
-
-        // Unsafe mechanics
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-        private static final long RIGHT;
-        static {
-            try {
-                RIGHT = U.objectFieldOffset
-                    (Index.class.getDeclaredField("right"));
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-        }
     }
 
-    /* ---------------- Head nodes -------------- */
-
-    /**
-     * Nodes heading each level keep track of their level.
-     */
-    static final class HeadIndex<K,V> extends Index<K,V> {
-        final int level;
-        HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
-            super(node, down, right);
-            this.level = level;
-        }
-    }
-
-    /* ---------------- Comparison utilities -------------- */
+    /* ----------------  Utilities -------------- */
 
     /**
      * Compares using comparator or natural ordering if null.
      * Called only by methods that have performed required type checks.
      */
     @SuppressWarnings({"unchecked", "rawtypes"})
-    static final int cpr(Comparator c, Object x, Object y) {
+    static int cpr(Comparator c, Object x, Object y) {
         return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
     }
 
+    /**
+     * Returns the header for base node list, or null if uninitialized
+     */
+    final Node<K,V> baseHead() {
+        Index<K,V> h;
+        VarHandle.acquireFence();
+        return ((h = head) == null) ? null : h.node;
+    }
+
+    /**
+     * Tries to unlink deleted node n from predecessor b (if both
+     * exist), by first splicing in a marker if not already present.
+     * Upon return, node n is sure to be unlinked from b, possibly
+     * via the actions of some other thread.
+     *
+     * @param b if nonnull, predecessor
+     * @param n if nonnull, node known to be deleted
+     */
+    static <K,V> void unlinkNode(Node<K,V> b, Node<K,V> n) {
+        if (b != null && n != null) {
+            Node<K,V> f, p;
+            for (;;) {
+                if ((f = n.next) != null && f.key == null) {
+                    p = f.next;               // already marked
+                    break;
+                }
+                else if (NEXT.compareAndSet(n, f,
+                                            new Node<K,V>(null, null, f))) {
+                    p = f;                    // add marker
+                    break;
+                }
+            }
+            NEXT.compareAndSet(b, n, p);
+        }
+    }
+
+    /**
+     * Adds to element count, initializing adder if necessary
+     *
+     * @param c count to add
+     */
+    private void addCount(long c) {
+        LongAdder a;
+        do {} while ((a = adder) == null &&
+                     !ADDER.compareAndSet(this, null, a = new LongAdder()));
+        a.add(c);
+    }
+
+    /**
+     * Returns element count, initializing adder if necessary.
+     */
+    final long getAdderCount() {
+        LongAdder a; long c;
+        do {} while ((a = adder) == null &&
+                     !ADDER.compareAndSet(this, null, a = new LongAdder()));
+        return ((c = a.sum()) <= 0L) ? 0L : c; // ignore transient negatives
+    }
+
     /* ---------------- Traversal -------------- */
 
     /**
-     * Returns a base-level node with key strictly less than given key,
-     * or the base-level header if there is no such node.  Also
-     * unlinks indexes to deleted nodes found along the way.  Callers
-     * rely on this side-effect of clearing indices to deleted nodes.
-     * @param key the key
-     * @return a predecessor of key
+     * Returns an index node with key strictly less than given key.
+     * Also unlinks indexes to deleted nodes found along the way.
+     * Callers rely on this side-effect of clearing indices to deleted
+     * nodes.
+     *
+     * @param key if nonnull the key
+     * @return a predecessor node of key, or null if uninitialized or null key
      */
     private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
-        if (key == null)
-            throw new NullPointerException(); // don't postpone errors
-        for (;;) {
-            for (Index<K,V> q = head, r = q.right, d;;) {
-                if (r != null) {
-                    Node<K,V> n = r.node;
-                    K k = n.key;
-                    if (n.value == null) {
-                        if (!q.unlink(r))
-                            break;           // restart
-                        r = q.right;         // reread r
-                        continue;
-                    }
-                    if (cpr(cmp, key, k) > 0) {
+        Index<K,V> q;
+        VarHandle.acquireFence();
+        if ((q = head) == null || key == null)
+            return null;
+        else {
+            for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p; K k;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        p.val == null)  // unlink index to deleted node
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if (cpr(cmp, key, k) > 0)
                         q = r;
-                        r = r.right;
-                        continue;
-                    }
+                    else
+                        break;
                 }
-                if ((d = q.down) == null)
+                if ((d = q.down) != null)
+                    q = d;
+                else
                     return q.node;
-                q = d;
-                r = d.right;
             }
         }
     }
@@ -693,41 +491,11 @@
      * deleted nodes seen along the way.  Repeatedly traverses at
      * base-level looking for key starting at predecessor returned
      * from findPredecessor, processing base-level deletions as
-     * encountered. Some callers rely on this side-effect of clearing
-     * deleted nodes.
-     *
-     * Restarts occur, at traversal step centered on node n, if:
-     *
-     *   (1) After reading n's next field, n is no longer assumed
-     *       predecessor b's current successor, which means that
-     *       we don't have a consistent 3-node snapshot and so cannot
-     *       unlink any subsequent deleted nodes encountered.
-     *
-     *   (2) n's value field is null, indicating n is deleted, in
-     *       which case we help out an ongoing structural deletion
-     *       before retrying.  Even though there are cases where such
-     *       unlinking doesn't require restart, they aren't sorted out
-     *       here because doing so would not usually outweigh cost of
-     *       restarting.
-     *
-     *   (3) n is a marker or n's predecessor's value field is null,
-     *       indicating (among other possibilities) that
-     *       findPredecessor returned a deleted node. We can't unlink
-     *       the node because we don't know its predecessor, so rely
-     *       on another call to findPredecessor to notice and return
-     *       some earlier predecessor, which it will do. This check is
-     *       only strictly needed at beginning of loop, (and the
-     *       b.value check isn't strictly needed at all) but is done
-     *       each iteration to help avoid contention with other
-     *       threads by callers that will fail to be able to change
-     *       links, and so will retry anyway.
-     *
-     * The traversal loops in doPut, doRemove, and findNear all
-     * include the same three kinds of checks. And specialized
-     * versions appear in findFirst, and findLast and their variants.
-     * They can't easily share code because each uses the reads of
-     * fields held in locals occurring in the orders they were
-     * performed.
+     * encountered. Restarts occur, at traversal step encountering
+     * node n, if n's key field is null, indicating it is a marker, so
+     * its predecessor is deleted before continuing, which we help do
+     * by re-finding a valid predecessor.  The traversal loops in
+     * doPut, doRemove, and findNear all include the same checks.
      *
      * @param key the key
      * @return node holding key, or null if no such
@@ -736,67 +504,81 @@
         if (key == null)
             throw new NullPointerException(); // don't postpone errors
         Comparator<? super K> cmp = comparator;
-        outer: for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                Object v; int c;
-                if (n == null)
-                    break outer;
-                Node<K,V> f = n.next;
-                if (n != b.next)                // inconsistent read
-                    break;
-                if ((v = n.value) == null) {    // n is deleted
-                    n.helpDelete(b, f);
-                    break;
-                }
-                if (b.value == null || v == n)  // b is deleted
-                    break;
-                if ((c = cpr(cmp, key, n.key)) == 0)
+        Node<K,V> b;
+        outer: while ((b = findPredecessor(key, cmp)) != null) {
+            for (;;) {
+                Node<K,V> n; K k; V v; int c;
+                if ((n = b.next) == null)
+                    break outer;               // empty
+                else if ((k = n.key) == null)
+                    break;                     // b is deleted
+                else if ((v = n.val) == null)
+                    unlinkNode(b, n);          // n is deleted
+                else if ((c = cpr(cmp, key, k)) > 0)
+                    b = n;
+                else if (c == 0)
                     return n;
-                if (c < 0)
+                else
                     break outer;
-                b = n;
-                n = f;
             }
         }
         return null;
     }
 
     /**
-     * Gets value for key. Almost the same as findNode, but returns
-     * the found value (to avoid retries during re-reads)
+     * Gets value for key. Same idea as findNode, except skips over
+     * deletions and markers, and returns first encountered value to
+     * avoid possibly inconsistent rereads.
      *
      * @param key the key
      * @return the value, or null if absent
      */
     private V doGet(Object key) {
+        Index<K,V> q;
+        VarHandle.acquireFence();
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        outer: for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                Object v; int c;
-                if (n == null)
-                    break outer;
-                Node<K,V> f = n.next;
-                if (n != b.next)                // inconsistent read
-                    break;
-                if ((v = n.value) == null) {    // n is deleted
-                    n.helpDelete(b, f);
+        V result = null;
+        if ((q = head) != null) {
+            outer: for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p; K k; V v; int c;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        (v = p.val) == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        q = r;
+                    else if (c == 0) {
+                        result = v;
+                        break outer;
+                    }
+                    else
+                        break;
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else {
+                    Node<K,V> b, n;
+                    if ((b = q.node) != null) {
+                        while ((n = b.next) != null) {
+                            V v; int c;
+                            K k = n.key;
+                            if ((v = n.val) == null || k == null ||
+                                (c = cpr(cmp, key, k)) > 0)
+                                b = n;
+                            else {
+                                if (c == 0)
+                                    result = v;
+                                break;
+                            }
+                        }
+                    }
                     break;
                 }
-                if (b.value == null || v == n)  // b is deleted
-                    break;
-                if ((c = cpr(cmp, key, n.key)) == 0) {
-                    @SuppressWarnings("unchecked") V vv = (V)v;
-                    return vv;
-                }
-                if (c < 0)
-                    break outer;
-                b = n;
-                n = f;
             }
         }
-        return null;
+        return result;
     }
 
     /* ---------------- Insertion -------------- */
@@ -804,126 +586,160 @@
     /**
      * Main insertion method.  Adds element if not present, or
      * replaces value if present and onlyIfAbsent is false.
+     *
      * @param key the key
      * @param value the value that must be associated with key
      * @param onlyIfAbsent if should not insert if already present
      * @return the old value, or null if newly inserted
      */
     private V doPut(K key, V value, boolean onlyIfAbsent) {
-        Node<K,V> z;             // added node
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        outer: for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                if (n != null) {
-                    Object v; int c;
-                    Node<K,V> f = n.next;
-                    if (n != b.next)               // inconsistent read
-                        break;
-                    if ((v = n.value) == null) {   // n is deleted
-                        n.helpDelete(b, f);
-                        break;
-                    }
-                    if (b.value == null || v == n) // b is deleted
-                        break;
-                    if ((c = cpr(cmp, key, n.key)) > 0) {
-                        b = n;
-                        n = f;
-                        continue;
-                    }
-                    if (c == 0) {
-                        if (onlyIfAbsent || n.casValue(v, value)) {
-                            @SuppressWarnings("unchecked") V vv = (V)v;
-                            return vv;
-                        }
-                        break; // restart if lost race to replace value
-                    }
-                    // else c < 0; fall through
-                }
-
-                z = new Node<K,V>(key, value, n);
-                if (!b.casNext(n, z))
-                    break;         // restart if lost race to append to b
-                break outer;
+        for (;;) {
+            Index<K,V> h; Node<K,V> b;
+            VarHandle.acquireFence();
+            int levels = 0;                    // number of levels descended
+            if ((h = head) == null) {          // try to initialize
+                Node<K,V> base = new Node<K,V>(null, null, null);
+                h = new Index<K,V>(base, null, null);
+                b = (HEAD.compareAndSet(this, null, h)) ? base : null;
             }
-        }
-
-        int rnd = ThreadLocalRandom.nextSecondarySeed();
-        if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
-            int level = 1, max;
-            while (((rnd >>>= 1) & 1) != 0)
-                ++level;
-            Index<K,V> idx = null;
-            HeadIndex<K,V> h = head;
-            if (level <= (max = h.level)) {
-                for (int i = 1; i <= level; ++i)
-                    idx = new Index<K,V>(z, idx, null);
-            }
-            else { // try to grow by one level
-                level = max + 1; // hold in array and later pick the one to use
-                @SuppressWarnings("unchecked")Index<K,V>[] idxs =
-                    (Index<K,V>[])new Index<?,?>[level+1];
-                for (int i = 1; i <= level; ++i)
-                    idxs[i] = idx = new Index<K,V>(z, idx, null);
-                for (;;) {
-                    h = head;
-                    int oldLevel = h.level;
-                    if (level <= oldLevel) // lost race to add level
-                        break;
-                    HeadIndex<K,V> newh = h;
-                    Node<K,V> oldbase = h.node;
-                    for (int j = oldLevel+1; j <= level; ++j)
-                        newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
-                    if (casHead(h, newh)) {
-                        h = newh;
-                        idx = idxs[level = oldLevel];
-                        break;
-                    }
-                }
-            }
-            // find insertion points and splice in
-            splice: for (int insertionLevel = level;;) {
-                int j = h.level;
-                for (Index<K,V> q = h, r = q.right, t = idx;;) {
-                    if (q == null || t == null)
-                        break splice;
-                    if (r != null) {
-                        Node<K,V> n = r.node;
-                        // compare before deletion check avoids needing recheck
-                        int c = cpr(cmp, key, n.key);
-                        if (n.value == null) {
-                            if (!q.unlink(r))
-                                break;
-                            r = q.right;
-                            continue;
-                        }
-                        if (c > 0) {
+            else {
+                for (Index<K,V> q = h, r, d;;) { // count while descending
+                    while ((r = q.right) != null) {
+                        Node<K,V> p; K k;
+                        if ((p = r.node) == null || (k = p.key) == null ||
+                            p.val == null)
+                            RIGHT.compareAndSet(q, r, r.right);
+                        else if (cpr(cmp, key, k) > 0)
                             q = r;
-                            r = r.right;
-                            continue;
-                        }
+                        else
+                            break;
                     }
-
-                    if (j == insertionLevel) {
-                        if (!q.link(r, t))
-                            break; // restart
-                        if (t.node.value == null) {
-                            findNode(key);
-                            break splice;
-                        }
-                        if (--insertionLevel == 0)
-                            break splice;
+                    if ((d = q.down) != null) {
+                        ++levels;
+                        q = d;
                     }
+                    else {
+                        b = q.node;
+                        break;
+                    }
+                }
+            }
+            if (b != null) {
+                Node<K,V> z = null;              // new node, if inserted
+                for (;;) {                       // find insertion point
+                    Node<K,V> n, p; K k; V v; int c;
+                    if ((n = b.next) == null) {
+                        if (b.key == null)       // if empty, type check key now
+                            cpr(cmp, key, key);
+                        c = -1;
+                    }
+                    else if ((k = n.key) == null)
+                        break;                   // can't append; restart
+                    else if ((v = n.val) == null) {
+                        unlinkNode(b, n);
+                        c = 1;
+                    }
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        b = n;
+                    else if (c == 0 &&
+                             (onlyIfAbsent || VAL.compareAndSet(n, v, value)))
+                        return v;
 
-                    if (--j >= insertionLevel && j < level)
-                        t = t.down;
-                    q = q.down;
-                    r = q.right;
+                    if (c < 0 &&
+                        NEXT.compareAndSet(b, n,
+                                           p = new Node<K,V>(key, value, n))) {
+                        z = p;
+                        break;
+                    }
+                }
+
+                if (z != null) {
+                    int lr = ThreadLocalRandom.nextSecondarySeed();
+                    if ((lr & 0x3) == 0) {       // add indices with 1/4 prob
+                        int hr = ThreadLocalRandom.nextSecondarySeed();
+                        long rnd = ((long)hr << 32) | ((long)lr & 0xffffffffL);
+                        int skips = levels;      // levels to descend before add
+                        Index<K,V> x = null;
+                        for (;;) {               // create at most 62 indices
+                            x = new Index<K,V>(z, x, null);
+                            if (rnd >= 0L || --skips < 0)
+                                break;
+                            else
+                                rnd <<= 1;
+                        }
+                        if (addIndices(h, skips, x, cmp) && skips < 0 &&
+                            head == h) {         // try to add new level
+                            Index<K,V> hx = new Index<K,V>(z, x, null);
+                            Index<K,V> nh = new Index<K,V>(h.node, h, hx);
+                            HEAD.compareAndSet(this, h, nh);
+                        }
+                        if (z.val == null)       // deleted while adding indices
+                            findPredecessor(key, cmp); // clean
+                    }
+                    addCount(1L);
+                    return null;
                 }
             }
         }
-        return null;
+    }
+
+    /**
+     * Add indices after an insertion. Descends iteratively to the
+     * highest level of insertion, then recursively, to chain index
+     * nodes to lower ones. Returns null on (staleness) failure,
+     * disabling higher-level insertions. Recursion depths are
+     * exponentially less probable.
+     *
+     * @param q starting index for current level
+     * @param skips levels to skip before inserting
+     * @param x index for this insertion
+     * @param cmp comparator
+     */
+    static <K,V> boolean addIndices(Index<K,V> q, int skips, Index<K,V> x,
+                                    Comparator<? super K> cmp) {
+        Node<K,V> z; K key;
+        if (x != null && (z = x.node) != null && (key = z.key) != null &&
+            q != null) {                            // hoist checks
+            boolean retrying = false;
+            for (;;) {                              // find splice point
+                Index<K,V> r, d; int c;
+                if ((r = q.right) != null) {
+                    Node<K,V> p; K k;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        p.val == null) {
+                        RIGHT.compareAndSet(q, r, r.right);
+                        c = 0;
+                    }
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        q = r;
+                    else if (c == 0)
+                        break;                      // stale
+                }
+                else
+                    c = -1;
+
+                if (c < 0) {
+                    if ((d = q.down) != null && skips > 0) {
+                        --skips;
+                        q = d;
+                    }
+                    else if (d != null && !retrying &&
+                             !addIndices(d, 0, x.down, cmp))
+                        break;
+                    else {
+                        x.right = r;
+                        if (RIGHT.compareAndSet(q, r, x))
+                            return true;
+                        else
+                            retrying = true;         // re-find splice point
+                    }
+                }
+            }
+        }
+        return false;
     }
 
     /* ---------------- Deletion -------------- */
@@ -933,15 +749,6 @@
      * deletion marker, unlinks predecessor, removes associated index
      * nodes, and possibly reduces head index level.
      *
-     * Index nodes are cleared out simply by calling findPredecessor.
-     * which unlinks indexes to deleted nodes found along path to key,
-     * which will include the indexes to this node.  This is done
-     * unconditionally. We can't check beforehand whether there are
-     * index nodes because it might be the case that some or all
-     * indexes hadn't been inserted yet for this node during initial
-     * search for it, and we'd like to ensure lack of garbage
-     * retention, so must call to be sure.
-     *
      * @param key the key
      * @param value if non-null, the value that must be
      * associated with key
@@ -951,43 +758,36 @@
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        outer: for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                Object v; int c;
-                if (n == null)
+        V result = null;
+        Node<K,V> b;
+        outer: while ((b = findPredecessor(key, cmp)) != null &&
+                      result == null) {
+            for (;;) {
+                Node<K,V> n; K k; V v; int c;
+                if ((n = b.next) == null)
                     break outer;
-                Node<K,V> f = n.next;
-                if (n != b.next)                    // inconsistent read
+                else if ((k = n.key) == null)
                     break;
-                if ((v = n.value) == null) {        // n is deleted
-                    n.helpDelete(b, f);
-                    break;
-                }
-                if (b.value == null || v == n)      // b is deleted
-                    break;
-                if ((c = cpr(cmp, key, n.key)) < 0)
-                    break outer;
-                if (c > 0) {
+                else if ((v = n.val) == null)
+                    unlinkNode(b, n);
+                else if ((c = cpr(cmp, key, k)) > 0)
                     b = n;
-                    n = f;
-                    continue;
-                }
-                if (value != null && !value.equals(v))
+                else if (c < 0)
                     break outer;
-                if (!n.casValue(v, null))
-                    break;
-                if (!n.appendMarker(f) || !b.casNext(n, f))
-                    findNode(key);                  // retry via findNode
-                else {
-                    findPredecessor(key, cmp);      // clean index
-                    if (head.right == null)
-                        tryReduceLevel();
+                else if (value != null && !value.equals(v))
+                    break outer;
+                else if (VAL.compareAndSet(n, v, null)) {
+                    result = v;
+                    unlinkNode(b, n);
+                    break; // loop to clean up
                 }
-                @SuppressWarnings("unchecked") V vv = (V)v;
-                return vv;
             }
         }
-        return null;
+        if (result != null) {
+            tryReduceLevel();
+            addCount(-1L);
+        }
+        return result;
     }
 
     /**
@@ -1011,125 +811,71 @@
      * reduction.
      */
     private void tryReduceLevel() {
-        HeadIndex<K,V> h = head;
-        HeadIndex<K,V> d;
-        HeadIndex<K,V> e;
-        if (h.level > 3 &&
-            (d = (HeadIndex<K,V>)h.down) != null &&
-            (e = (HeadIndex<K,V>)d.down) != null &&
-            e.right == null &&
-            d.right == null &&
-            h.right == null &&
-            casHead(h, d) && // try to set
-            h.right != null) // recheck
-            casHead(d, h);   // try to backout
+        Index<K,V> h, d, e;
+        if ((h = head) != null && h.right == null &&
+            (d = h.down) != null && d.right == null &&
+            (e = d.down) != null && e.right == null &&
+            HEAD.compareAndSet(this, h, d) &&
+            h.right != null)   // recheck
+            HEAD.compareAndSet(this, d, h);  // try to backout
     }
 
     /* ---------------- Finding and removing first element -------------- */
 
     /**
-     * Specialized variant of findNode to get first valid node.
+     * Gets first valid node, unlinking deleted nodes if encountered.
      * @return first node or null if empty
      */
     final Node<K,V> findFirst() {
-        for (Node<K,V> b, n;;) {
-            if ((n = (b = head.node).next) == null)
-                return null;
-            if (n.value != null)
-                return n;
-            n.helpDelete(b, n.next);
+        Node<K,V> b, n;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if (n.val == null)
+                    unlinkNode(b, n);
+                else
+                    return n;
+            }
         }
+        return null;
+    }
+
+    /**
+     * Entry snapshot version of findFirst
+     */
+    final AbstractMap.SimpleImmutableEntry<K,V> findFirstEntry() {
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) == null)
+                    unlinkNode(b, n);
+                else
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            }
+        }
+        return null;
     }
 
     /**
      * Removes first entry; returns its snapshot.
      * @return null if empty, else snapshot of first entry
      */
-    private Map.Entry<K,V> doRemoveFirstEntry() {
-        for (Node<K,V> b, n;;) {
-            if ((n = (b = head.node).next) == null)
-                return null;
-            Node<K,V> f = n.next;
-            if (n != b.next)
-                continue;
-            Object v = n.value;
-            if (v == null) {
-                n.helpDelete(b, f);
-                continue;
-            }
-            if (!n.casValue(v, null))
-                continue;
-            if (!n.appendMarker(f) || !b.casNext(n, f))
-                findFirst(); // retry
-            clearIndexToFirst();
-            @SuppressWarnings("unchecked") V vv = (V)v;
-            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, vv);
-        }
-    }
-
-    /**
-     * Clears out index nodes associated with deleted first entry.
-     */
-    private void clearIndexToFirst() {
-        for (;;) {
-            for (Index<K,V> q = head;;) {
-                Index<K,V> r = q.right;
-                if (r != null && r.indexesDeletedNode() && !q.unlink(r))
-                    break;
-                if ((q = q.down) == null) {
-                    if (head.right == null)
+    private AbstractMap.SimpleImmutableEntry<K,V> doRemoveFirstEntry() {
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) == null || VAL.compareAndSet(n, v, null)) {
+                    K k = n.key;
+                    unlinkNode(b, n);
+                    if (v != null) {
                         tryReduceLevel();
-                    return;
+                        findPredecessor(k, comparator); // clean index
+                        addCount(-1L);
+                        return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+                    }
                 }
             }
         }
-    }
-
-    /**
-     * Removes last entry; returns its snapshot.
-     * Specialized variant of doRemove.
-     * @return null if empty, else snapshot of last entry
-     */
-    private Map.Entry<K,V> doRemoveLastEntry() {
-        for (;;) {
-            Node<K,V> b = findPredecessorOfLast();
-            Node<K,V> n = b.next;
-            if (n == null) {
-                if (b.isBaseHeader())               // empty
-                    return null;
-                else
-                    continue; // all b's successors are deleted; retry
-            }
-            for (;;) {
-                Node<K,V> f = n.next;
-                if (n != b.next)                    // inconsistent read
-                    break;
-                Object v = n.value;
-                if (v == null) {                    // n is deleted
-                    n.helpDelete(b, f);
-                    break;
-                }
-                if (b.value == null || v == n)      // b is deleted
-                    break;
-                if (f != null) {
-                    b = n;
-                    n = f;
-                    continue;
-                }
-                if (!n.casValue(v, null))
-                    break;
-                K key = n.key;
-                if (!n.appendMarker(f) || !b.casNext(n, f))
-                    findNode(key);                  // retry via findNode
-                else {                              // clean index
-                    findPredecessor(key, comparator);
-                    if (head.right == null)
-                        tryReduceLevel();
-                }
-                @SuppressWarnings("unchecked") V vv = (V)v;
-                return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
-            }
-        }
+        return null;
     }
 
     /* ---------------- Finding and removing last element -------------- */
@@ -1139,73 +885,115 @@
      * @return last node or null if empty
      */
     final Node<K,V> findLast() {
-        /*
-         * findPredecessor can't be used to traverse index level
-         * because this doesn't use comparisons.  So traversals of
-         * both levels are folded together.
-         */
-        Index<K,V> q = head;
-        for (;;) {
-            Index<K,V> d, r;
-            if ((r = q.right) != null) {
-                if (r.indexesDeletedNode()) {
-                    q.unlink(r);
-                    q = head; // restart
+        outer: for (;;) {
+            Index<K,V> q; Node<K,V> b;
+            VarHandle.acquireFence();
+            if ((q = head) == null)
+                break;
+            for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p;
+                    if ((p = r.node) == null || p.val == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else
+                        q = r;
                 }
-                else
-                    q = r;
-            } else if ((d = q.down) != null) {
-                q = d;
-            } else {
-                for (Node<K,V> b = q.node, n = b.next;;) {
-                    if (n == null)
-                        return b.isBaseHeader() ? null : b;
-                    Node<K,V> f = n.next;            // inconsistent read
-                    if (n != b.next)
-                        break;
-                    Object v = n.value;
-                    if (v == null) {                 // n is deleted
-                        n.helpDelete(b, f);
-                        break;
-                    }
-                    if (b.value == null || v == n)      // b is deleted
-                        break;
-                    b = n;
-                    n = f;
+                if ((d = q.down) != null)
+                    q = d;
+                else {
+                    b = q.node;
+                    break;
                 }
-                q = head; // restart
             }
+            if (b != null) {
+                for (;;) {
+                    Node<K,V> n;
+                    if ((n = b.next) == null) {
+                        if (b.key == null) // empty
+                            break outer;
+                        else
+                            return b;
+                    }
+                    else if (n.key == null)
+                        break;
+                    else if (n.val == null)
+                        unlinkNode(b, n);
+                    else
+                        b = n;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Entry version of findLast
+     * @return Entry for last node or null if empty
+     */
+    final AbstractMap.SimpleImmutableEntry<K,V> findLastEntry() {
+        for (;;) {
+            Node<K,V> n; V v;
+            if ((n = findLast()) == null)
+                return null;
+            if ((v = n.val) != null)
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
         }
     }
 
     /**
-     * Specialized variant of findPredecessor to get predecessor of last
-     * valid node.  Needed when removing the last entry.  It is possible
-     * that all successors of returned node will have been deleted upon
-     * return, in which case this method can be retried.
-     * @return likely predecessor of last node
+     * Removes last entry; returns its snapshot.
+     * Specialized variant of doRemove.
+     * @return null if empty, else snapshot of last entry
      */
-    private Node<K,V> findPredecessorOfLast() {
-        for (;;) {
-            for (Index<K,V> q = head;;) {
-                Index<K,V> d, r;
-                if ((r = q.right) != null) {
-                    if (r.indexesDeletedNode()) {
-                        q.unlink(r);
-                        break;    // must restart
-                    }
-                    // proceed as far across as possible without overshooting
-                    if (r.node.next != null) {
-                        q = r;
-                        continue;
-                    }
+    private Map.Entry<K,V> doRemoveLastEntry() {
+        outer: for (;;) {
+            Index<K,V> q; Node<K,V> b;
+            VarHandle.acquireFence();
+            if ((q = head) == null)
+                break;
+            for (;;) {
+                Index<K,V> d, r; Node<K,V> p;
+                while ((r = q.right) != null) {
+                    if ((p = r.node) == null || p.val == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if (p.next != null)
+                        q = r;  // continue only if a successor
+                    else
+                        break;
                 }
                 if ((d = q.down) != null)
                     q = d;
-                else
-                    return q.node;
+                else {
+                    b = q.node;
+                    break;
+                }
+            }
+            if (b != null) {
+                for (;;) {
+                    Node<K,V> n; K k; V v;
+                    if ((n = b.next) == null) {
+                        if (b.key == null) // empty
+                            break outer;
+                        else
+                            break; // retry
+                    }
+                    else if ((k = n.key) == null)
+                        break;
+                    else if ((v = n.val) == null)
+                        unlinkNode(b, n);
+                    else if (n.next != null)
+                        b = n;
+                    else if (VAL.compareAndSet(n, v, null)) {
+                        unlinkNode(b, n);
+                        tryReduceLevel();
+                        findPredecessor(k, comparator); // clean index
+                        addCount(-1L);
+                        return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+                    }
+                }
             }
         }
+        return null;
     }
 
     /* ---------------- Relational operations -------------- */
@@ -1225,47 +1013,52 @@
     final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
         if (key == null)
             throw new NullPointerException();
-        for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                Object v;
-                if (n == null)
-                    return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
-                Node<K,V> f = n.next;
-                if (n != b.next)                  // inconsistent read
-                    break;
-                if ((v = n.value) == null) {      // n is deleted
-                    n.helpDelete(b, f);
-                    break;
+        Node<K,V> result;
+        outer: for (Node<K,V> b;;) {
+            if ((b = findPredecessor(key, cmp)) == null) {
+                result = null;
+                break;                   // empty
+            }
+            for (;;) {
+                Node<K,V> n; K k; int c;
+                if ((n = b.next) == null) {
+                    result = ((rel & LT) != 0 && b.key != null) ? b : null;
+                    break outer;
                 }
-                if (b.value == null || v == n)      // b is deleted
+                else if ((k = n.key) == null)
                     break;
-                int c = cpr(cmp, key, n.key);
-                if ((c == 0 && (rel & EQ) != 0) ||
-                    (c <  0 && (rel & LT) == 0))
-                    return n;
-                if ( c <= 0 && (rel & LT) != 0)
-                    return b.isBaseHeader() ? null : b;
-                b = n;
-                n = f;
+                else if (n.val == null)
+                    unlinkNode(b, n);
+                else if (((c = cpr(cmp, key, k)) == 0 && (rel & EQ) != 0) ||
+                         (c < 0 && (rel & LT) == 0)) {
+                    result = n;
+                    break outer;
+                }
+                else if (c <= 0 && (rel & LT) != 0) {
+                    result = (b.key != null) ? b : null;
+                    break outer;
+                }
+                else
+                    b = n;
             }
         }
+        return result;
     }
 
     /**
-     * Returns SimpleImmutableEntry for results of findNear.
+     * Variant of findNear returning SimpleImmutableEntry
      * @param key the key
      * @param rel the relation -- OR'ed combination of EQ, LT, GT
      * @return Entry fitting relation, or null if no such
      */
-    final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
-        Comparator<? super K> cmp = comparator;
+    final AbstractMap.SimpleImmutableEntry<K,V> findNearEntry(K key, int rel,
+                                                              Comparator<? super K> cmp) {
         for (;;) {
-            Node<K,V> n = findNear(key, rel, cmp);
-            if (n == null)
+            Node<K,V> n; V v;
+            if ((n = findNear(key, rel, cmp)) == null)
                 return null;
-            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
-            if (e != null)
-                return e;
+            if ((v = n.val) != null)
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
         }
     }
 
@@ -1277,7 +1070,6 @@
      */
     public ConcurrentSkipListMap() {
         this.comparator = null;
-        initialize();
     }
 
     /**
@@ -1290,7 +1082,6 @@
      */
     public ConcurrentSkipListMap(Comparator<? super K> comparator) {
         this.comparator = comparator;
-        initialize();
     }
 
     /**
@@ -1306,7 +1097,6 @@
      */
     public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
         this.comparator = null;
-        initialize();
         putAll(m);
     }
 
@@ -1321,8 +1111,7 @@
      */
     public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
         this.comparator = m.comparator();
-        initialize();
-        buildFromSorted(m);
+        buildFromSorted(m); // initializes transients
     }
 
     /**
@@ -1336,7 +1125,10 @@
             @SuppressWarnings("unchecked")
             ConcurrentSkipListMap<K,V> clone =
                 (ConcurrentSkipListMap<K,V>) super.clone();
-            clone.initialize();
+            clone.keySet = null;
+            clone.entrySet = null;
+            clone.values = null;
+            clone.descendingMap = null;
             clone.buildFromSorted(this);
             return clone;
         } catch (CloneNotSupportedException e) {
@@ -1352,58 +1144,49 @@
     private void buildFromSorted(SortedMap<K, ? extends V> map) {
         if (map == null)
             throw new NullPointerException();
-
-        HeadIndex<K,V> h = head;
-        Node<K,V> basepred = h.node;
-
-        // Track the current rightmost node at each level. Uses an
-        // ArrayList to avoid committing to initial or maximum level.
-        ArrayList<Index<K,V>> preds = new ArrayList<>();
-
-        // initialize
-        for (int i = 0; i <= h.level; ++i)
-            preds.add(null);
-        Index<K,V> q = h;
-        for (int i = h.level; i > 0; --i) {
-            preds.set(i, q);
-            q = q.down;
-        }
-
         Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
             map.entrySet().iterator();
+
+        /*
+         * Add equally spaced indices at log intervals, using the bits
+         * of count during insertion. The maximum possible resulting
+         * level is less than the number of bits in a long (64). The
+         * preds array tracks the current rightmost node at each
+         * level.
+         */
+        @SuppressWarnings("unchecked")
+        Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+        Node<K,V> bp = new Node<K,V>(null, null, null);
+        Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+        long count = 0;
+
         while (it.hasNext()) {
             Map.Entry<? extends K, ? extends V> e = it.next();
-            int rnd = ThreadLocalRandom.current().nextInt();
-            int j = 0;
-            if ((rnd & 0x80000001) == 0) {
-                do {
-                    ++j;
-                } while (((rnd >>>= 1) & 1) != 0);
-                if (j > h.level) j = h.level + 1;
-            }
             K k = e.getKey();
             V v = e.getValue();
             if (k == null || v == null)
                 throw new NullPointerException();
             Node<K,V> z = new Node<K,V>(k, v, null);
-            basepred.next = z;
-            basepred = z;
-            if (j > 0) {
-                Index<K,V> idx = null;
-                for (int i = 1; i <= j; ++i) {
+            bp = bp.next = z;
+            if ((++count & 3L) == 0L) {
+                long m = count >>> 2;
+                int i = 0;
+                Index<K,V> idx = null, q;
+                do {
                     idx = new Index<K,V>(z, idx, null);
-                    if (i > h.level)
-                        h = new HeadIndex<K,V>(h.node, h, idx, i);
-
-                    if (i < preds.size()) {
-                        preds.get(i).right = idx;
-                        preds.set(i, idx);
-                    } else
-                        preds.add(idx);
-                }
+                    if ((q = preds[i]) == null)
+                        preds[i] = h = new Index<K,V>(h.node, h, idx);
+                    else
+                        preds[i] = q.right = idx;
+                } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
             }
         }
-        head = h;
+        if (count != 0L) {
+            VarHandle.releaseFence(); // emulate volatile stores
+            addCount(count);
+            head = h;
+            VarHandle.fullFence();
+        }
     }
 
     /* ---------------- Serialization -------------- */
@@ -1425,11 +1208,14 @@
         s.defaultWriteObject();
 
         // Write out keys and values (alternating)
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            V v = n.getValidValue();
-            if (v != null) {
-                s.writeObject(n.key);
-                s.writeObject(v);
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null) {
+                    s.writeObject(n.key);
+                    s.writeObject(v);
+                }
+                b = n;
             }
         }
         s.writeObject(null);
@@ -1447,64 +1233,47 @@
         throws java.io.IOException, ClassNotFoundException {
         // Read in the Comparator and any hidden stuff
         s.defaultReadObject();
-        // Reset transients
-        initialize();
 
-        /*
-         * This is nearly identical to buildFromSorted, but is
-         * distinct because readObject calls can't be nicely adapted
-         * as the kind of iterator needed by buildFromSorted. (They
-         * can be, but doing so requires type cheats and/or creation
-         * of adapter classes.) It is simpler to just adapt the code.
-         */
-
-        HeadIndex<K,V> h = head;
-        Node<K,V> basepred = h.node;
-        ArrayList<Index<K,V>> preds = new ArrayList<>();
-        for (int i = 0; i <= h.level; ++i)
-            preds.add(null);
-        Index<K,V> q = h;
-        for (int i = h.level; i > 0; --i) {
-            preds.set(i, q);
-            q = q.down;
-        }
+        // Same idea as buildFromSorted
+        @SuppressWarnings("unchecked")
+        Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+        Node<K,V> bp = new Node<K,V>(null, null, null);
+        Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+        Comparator<? super K> cmp = comparator;
+        K prevKey = null;
+        long count = 0;
 
         for (;;) {
-            Object k = s.readObject();
+            K k = (K)s.readObject();
             if (k == null)
                 break;
-            Object v = s.readObject();
+            V v = (V)s.readObject();
             if (v == null)
                 throw new NullPointerException();
-            K key = (K) k;
-            V val = (V) v;
-            int rnd = ThreadLocalRandom.current().nextInt();
-            int j = 0;
-            if ((rnd & 0x80000001) == 0) {
+            if (prevKey != null && cpr(cmp, prevKey, k) > 0)
+                throw new IllegalStateException("out of order");
+            prevKey = k;
+            Node<K,V> z = new Node<K,V>(k, v, null);
+            bp = bp.next = z;
+            if ((++count & 3L) == 0L) {
+                long m = count >>> 2;
+                int i = 0;
+                Index<K,V> idx = null, q;
                 do {
-                    ++j;
-                } while (((rnd >>>= 1) & 1) != 0);
-                if (j > h.level) j = h.level + 1;
-            }
-            Node<K,V> z = new Node<K,V>(key, val, null);
-            basepred.next = z;
-            basepred = z;
-            if (j > 0) {
-                Index<K,V> idx = null;
-                for (int i = 1; i <= j; ++i) {
                     idx = new Index<K,V>(z, idx, null);
-                    if (i > h.level)
-                        h = new HeadIndex<K,V>(h.node, h, idx, i);
-
-                    if (i < preds.size()) {
-                        preds.get(i).right = idx;
-                        preds.set(i, idx);
-                    } else
-                        preds.add(idx);
-                }
+                    if ((q = preds[i]) == null)
+                        preds[i] = h = new Index<K,V>(h.node, h, idx);
+                    else
+                        preds[i] = q.right = idx;
+                } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
             }
         }
-        head = h;
+        if (count != 0L) {
+            VarHandle.releaseFence();
+            addCount(count);
+            head = h;
+            VarHandle.fullFence();
+        }
     }
 
     /* ------ Map API methods ------ */
@@ -1605,42 +1374,30 @@
     public boolean containsValue(Object value) {
         if (value == null)
             throw new NullPointerException();
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            V v = n.getValidValue();
-            if (v != null && value.equals(v))
-                return true;
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null && value.equals(v))
+                    return true;
+                else
+                    b = n;
+            }
         }
         return false;
     }
 
     /**
-     * Returns the number of key-value mappings in this map.  If this map
-     * contains more than {@code Integer.MAX_VALUE} elements, it
-     * returns {@code Integer.MAX_VALUE}.
-     *
-     * <p>Beware that, unlike in most collections, this method is
-     * <em>NOT</em> a constant-time operation. Because of the
-     * asynchronous nature of these maps, determining the current
-     * number of elements requires traversing them all to count them.
-     * Additionally, it is possible for the size to change during
-     * execution of this method, in which case the returned result
-     * will be inaccurate. Thus, this method is typically not very
-     * useful in concurrent applications.
-     *
-     * @return the number of elements in this map
+     * {@inheritDoc}
      */
     public int size() {
-        long count = 0;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            if (n.getValidValue() != null)
-                ++count;
-        }
-        return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
+        long c;
+        return ((baseHead() == null) ? 0 :
+                ((c = getAdderCount()) >= Integer.MAX_VALUE) ?
+                Integer.MAX_VALUE : (int) c);
     }
 
     /**
-     * Returns {@code true} if this map contains no key-value mappings.
-     * @return {@code true} if this map contains no key-value mappings
+     * {@inheritDoc}
      */
     public boolean isEmpty() {
         return findFirst() == null;
@@ -1650,7 +1407,33 @@
      * Removes all of the mappings from this map.
      */
     public void clear() {
-        initialize();
+        Index<K,V> h, r, d; Node<K,V> b;
+        VarHandle.acquireFence();
+        while ((h = head) != null) {
+            if ((r = h.right) != null)        // remove indices
+                RIGHT.compareAndSet(h, r, null);
+            else if ((d = h.down) != null)    // remove levels
+                HEAD.compareAndSet(this, h, d);
+            else {
+                long count = 0L;
+                if ((b = h.node) != null) {    // remove nodes
+                    Node<K,V> n; V v;
+                    while ((n = b.next) != null) {
+                        if ((v = n.val) != null &&
+                            VAL.compareAndSet(n, v, null)) {
+                            --count;
+                            v = null;
+                        }
+                        if (v == null)
+                            unlinkNode(b, n);
+                    }
+                }
+                if (count != 0L)
+                    addCount(count);
+                else
+                    break;
+            }
+        }
     }
 
     /**
@@ -1696,16 +1479,15 @@
                               BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
         if (key == null || remappingFunction == null)
             throw new NullPointerException();
-        Node<K,V> n; Object v;
+        Node<K,V> n; V v;
         while ((n = findNode(key)) != null) {
-            if ((v = n.value) != null) {
-                @SuppressWarnings("unchecked") V vv = (V) v;
-                V r = remappingFunction.apply(key, vv);
+            if ((v = n.val) != null) {
+                V r = remappingFunction.apply(key, v);
                 if (r != null) {
-                    if (n.casValue(vv, r))
+                    if (VAL.compareAndSet(n, v, r))
                         return r;
                 }
-                else if (doRemove(key, vv) != null)
+                else if (doRemove(key, v) != null)
                     break;
             }
         }
@@ -1730,20 +1512,19 @@
         if (key == null || remappingFunction == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; Object v; V r;
+            Node<K,V> n; V v; V r;
             if ((n = findNode(key)) == null) {
                 if ((r = remappingFunction.apply(key, null)) == null)
                     break;
                 if (doPut(key, r, true) == null)
                     return r;
             }
-            else if ((v = n.value) != null) {
-                @SuppressWarnings("unchecked") V vv = (V) v;
-                if ((r = remappingFunction.apply(key, vv)) != null) {
-                    if (n.casValue(vv, r))
+            else if ((v = n.val) != null) {
+                if ((r = remappingFunction.apply(key, v)) != null) {
+                    if (VAL.compareAndSet(n, v, r))
                         return r;
                 }
-                else if (doRemove(key, vv) != null)
+                else if (doRemove(key, v) != null)
                     break;
             }
         }
@@ -1770,18 +1551,17 @@
         if (key == null || value == null || remappingFunction == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; Object v; V r;
+            Node<K,V> n; V v; V r;
             if ((n = findNode(key)) == null) {
                 if (doPut(key, value, true) == null)
                     return value;
             }
-            else if ((v = n.value) != null) {
-                @SuppressWarnings("unchecked") V vv = (V) v;
-                if ((r = remappingFunction.apply(vv, value)) != null) {
-                    if (n.casValue(vv, r))
+            else if ((v = n.val) != null) {
+                if ((r = remappingFunction.apply(v, value)) != null) {
+                    if (VAL.compareAndSet(n, v, r))
                         return r;
                 }
-                else if (doRemove(key, vv) != null)
+                else if (doRemove(key, v) != null)
                     return null;
             }
         }
@@ -1805,9 +1585,11 @@
      * The set's spliterator additionally reports {@link Spliterator#CONCURRENT},
      * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
      * {@link Spliterator#ORDERED}, with an encounter order that is ascending
-     * key order.  The spliterator's comparator (see
-     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
-     * the map's comparator (see {@link #comparator()}) is {@code null}.
+     * key order.
+     *
+     * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
+     * is {@code null} if the {@linkplain #comparator() map's comparator}
+     * is {@code null}.
      * Otherwise, the spliterator's comparator is the same as or imposes the
      * same total ordering as the map's comparator.
      *
@@ -1827,13 +1609,15 @@
      * @return a navigable set view of the keys in this map
      */
     public NavigableSet<K> keySet() {
-        KeySet<K,V> ks = keySet;
-        return (ks != null) ? ks : (keySet = new KeySet<>(this));
+        KeySet<K,V> ks;
+        if ((ks = keySet) != null) return ks;
+        return keySet = new KeySet<>(this);
     }
 
     public NavigableSet<K> navigableKeySet() {
-        KeySet<K,V> ks = keySet;
-        return (ks != null) ? ks : (keySet = new KeySet<>(this));
+        KeySet<K,V> ks;
+        if ((ks = keySet) != null) return ks;
+        return keySet = new KeySet<>(this);
     }
 
     /**
@@ -1856,8 +1640,9 @@
      * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
      */
     public Collection<V> values() {
-        Values<K,V> vs = values;
-        return (vs != null) ? vs : (values = new Values<>(this));
+        Values<K,V> vs;
+        if ((vs = values) != null) return vs;
+        return values = new Values<>(this);
     }
 
     /**
@@ -1888,14 +1673,16 @@
      *         sorted in ascending key order
      */
     public Set<Map.Entry<K,V>> entrySet() {
-        EntrySet<K,V> es = entrySet;
-        return (es != null) ? es : (entrySet = new EntrySet<K,V>(this));
+        EntrySet<K,V> es;
+        if ((es = entrySet) != null) return es;
+        return entrySet = new EntrySet<K,V>(this);
     }
 
     public ConcurrentNavigableMap<K,V> descendingMap() {
-        ConcurrentNavigableMap<K,V> dm = descendingMap;
-        return (dm != null) ? dm : (descendingMap = new SubMap<K,V>
-                                    (this, null, false, null, false, true));
+        ConcurrentNavigableMap<K,V> dm;
+        if ((dm = descendingMap) != null) return dm;
+        return descendingMap =
+            new SubMap<K,V>(this, null, false, null, false, true);
     }
 
     public NavigableSet<K> descendingKeySet() {
@@ -1923,19 +1710,61 @@
             return false;
         Map<?,?> m = (Map<?,?>) o;
         try {
-            for (Map.Entry<K,V> e : this.entrySet())
-                if (! e.getValue().equals(m.get(e.getKey())))
-                    return false;
-            for (Map.Entry<?,?> e : m.entrySet()) {
-                Object k = e.getKey();
-                Object v = e.getValue();
-                if (k == null || v == null || !v.equals(get(k)))
-                    return false;
+            Comparator<? super K> cmp = comparator;
+            @SuppressWarnings("unchecked")
+            Iterator<Map.Entry<?,?>> it =
+                (Iterator<Map.Entry<?,?>>)m.entrySet().iterator();
+            if (m instanceof SortedMap &&
+                ((SortedMap<?,?>)m).comparator() == cmp) {
+                Node<K,V> b, n;
+                if ((b = baseHead()) != null) {
+                    while ((n = b.next) != null) {
+                        K k; V v;
+                        if ((v = n.val) != null && (k = n.key) != null) {
+                            if (!it.hasNext())
+                                return false;
+                            Map.Entry<?,?> e = it.next();
+                            Object mk = e.getKey();
+                            Object mv = e.getValue();
+                            if (mk == null || mv == null)
+                                return false;
+                            try {
+                                if (cpr(cmp, k, mk) != 0)
+                                    return false;
+                            } catch (ClassCastException cce) {
+                                return false;
+                            }
+                            if (!mv.equals(v))
+                                return false;
+                        }
+                        b = n;
+                    }
+                }
+                return !it.hasNext();
             }
-            return true;
-        } catch (ClassCastException unused) {
-            return false;
-        } catch (NullPointerException unused) {
+            else {
+                while (it.hasNext()) {
+                    V v;
+                    Map.Entry<?,?> e = it.next();
+                    Object mk = e.getKey();
+                    Object mv = e.getValue();
+                    if (mk == null || mv == null ||
+                        (v = get(mk)) == null || !v.equals(mv))
+                        return false;
+                }
+                Node<K,V> b, n;
+                if ((b = baseHead()) != null) {
+                    K k; V v; Object mv;
+                    while ((n = b.next) != null) {
+                        if ((v = n.val) != null && (k = n.key) != null &&
+                            ((mv = m.get(k)) == null || !mv.equals(v)))
+                            return false;
+                        b = n;
+                    }
+                }
+                return true;
+            }
+        } catch (ClassCastException | NullPointerException unused) {
             return false;
         }
     }
@@ -1981,13 +1810,13 @@
         if (key == null || oldValue == null || newValue == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; Object v;
+            Node<K,V> n; V v;
             if ((n = findNode(key)) == null)
                 return false;
-            if ((v = n.value) != null) {
+            if ((v = n.val) != null) {
                 if (!oldValue.equals(v))
                     return false;
-                if (n.casValue(v, newValue))
+                if (VAL.compareAndSet(n, v, newValue))
                     return true;
             }
         }
@@ -2006,13 +1835,11 @@
         if (key == null || value == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; Object v;
+            Node<K,V> n; V v;
             if ((n = findNode(key)) == null)
                 return null;
-            if ((v = n.value) != null && n.casValue(v, value)) {
-                @SuppressWarnings("unchecked") V vv = (V)v;
-                return vv;
-            }
+            if ((v = n.val) != null && VAL.compareAndSet(n, v, value))
+                return v;
         }
     }
 
@@ -2122,7 +1949,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> lowerEntry(K key) {
-        return getNear(key, LT);
+        return findNearEntry(key, LT, comparator);
     }
 
     /**
@@ -2145,7 +1972,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> floorEntry(K key) {
-        return getNear(key, LT|EQ);
+        return findNearEntry(key, LT|EQ, comparator);
     }
 
     /**
@@ -2168,7 +1995,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> ceilingEntry(K key) {
-        return getNear(key, GT|EQ);
+        return findNearEntry(key, GT|EQ, comparator);
     }
 
     /**
@@ -2191,7 +2018,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> higherEntry(K key) {
-        return getNear(key, GT);
+        return findNearEntry(key, GT, comparator);
     }
 
     /**
@@ -2211,14 +2038,7 @@
      * the {@code Entry.setValue} method.
      */
     public Map.Entry<K,V> firstEntry() {
-        for (;;) {
-            Node<K,V> n = findFirst();
-            if (n == null)
-                return null;
-            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
-            if (e != null)
-                return e;
-        }
+        return findFirstEntry();
     }
 
     /**
@@ -2228,14 +2048,7 @@
      * the {@code Entry.setValue} method.
      */
     public Map.Entry<K,V> lastEntry() {
-        for (;;) {
-            Node<K,V> n = findLast();
-            if (n == null)
-                return null;
-            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
-            if (e != null)
-                return e;
-        }
+        return findLastEntry();
     }
 
     /**
@@ -2258,11 +2071,10 @@
         return doRemoveLastEntry();
     }
 
-
     /* ---------------- Iterators -------------- */
 
     /**
-     * Base of iterator classes:
+     * Base of iterator classes
      */
     abstract class Iter<T> implements Iterator<T> {
         /** the last node returned by next() */
@@ -2274,14 +2086,7 @@
 
         /** Initializes ascending iterator for entire range. */
         Iter() {
-            while ((next = findFirst()) != null) {
-                Object x = next.value;
-                if (x != null && x != next) {
-                    @SuppressWarnings("unchecked") V vv = (V)x;
-                    nextValue = vv;
-                    break;
-                }
-            }
+            advance(baseHead());
         }
 
         public final boolean hasNext() {
@@ -2289,54 +2094,58 @@
         }
 
         /** Advances next to higher entry. */
-        final void advance() {
-            if (next == null)
-                throw new NoSuchElementException();
-            lastReturned = next;
-            while ((next = next.next) != null) {
-                Object x = next.value;
-                if (x != null && x != next) {
-                    @SuppressWarnings("unchecked") V vv = (V)x;
-                    nextValue = vv;
-                    break;
-                }
+        final void advance(Node<K,V> b) {
+            Node<K,V> n = null;
+            V v = null;
+            if ((lastReturned = b) != null) {
+                while ((n = b.next) != null && (v = n.val) == null)
+                    b = n;
             }
+            nextValue = v;
+            next = n;
         }
 
-        public void remove() {
-            Node<K,V> l = lastReturned;
-            if (l == null)
+        public final void remove() {
+            Node<K,V> n; K k;
+            if ((n = lastReturned) == null || (k = n.key) == null)
                 throw new IllegalStateException();
             // It would not be worth all of the overhead to directly
             // unlink from here. Using remove is fast enough.
-            ConcurrentSkipListMap.this.remove(l.key);
+            ConcurrentSkipListMap.this.remove(k);
             lastReturned = null;
         }
-
     }
 
     final class ValueIterator extends Iter<V> {
         public V next() {
-            V v = nextValue;
-            advance();
+            V v;
+            if ((v = nextValue) == null)
+                throw new NoSuchElementException();
+            advance(next);
             return v;
         }
     }
 
     final class KeyIterator extends Iter<K> {
         public K next() {
-            Node<K,V> n = next;
-            advance();
-            return n.key;
+            Node<K,V> n;
+            if ((n = next) == null)
+                throw new NoSuchElementException();
+            K k = n.key;
+            advance(n);
+            return k;
         }
     }
 
     final class EntryIterator extends Iter<Map.Entry<K,V>> {
         public Map.Entry<K,V> next() {
-            Node<K,V> n = next;
+            Node<K,V> n;
+            if ((n = next) == null)
+                throw new NoSuchElementException();
+            K k = n.key;
             V v = nextValue;
-            advance();
-            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            advance(n);
+            return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
         }
     }
 
@@ -2393,9 +2202,7 @@
             Collection<?> c = (Collection<?>) o;
             try {
                 return containsAll(c) && c.containsAll(this);
-            } catch (ClassCastException unused) {
-                return false;
-            } catch (NullPointerException unused) {
+            } catch (ClassCastException | NullPointerException unused) {
                 return false;
             }
         }
@@ -2520,9 +2327,7 @@
             Collection<?> c = (Collection<?>) o;
             try {
                 return containsAll(c) && c.containsAll(this);
-            } catch (ClassCastException unused) {
-                return false;
-            } catch (NullPointerException unused) {
+            } catch (ClassCastException | NullPointerException unused) {
                 return false;
             }
         }
@@ -2564,7 +2369,7 @@
      * @serial include
      */
     static final class SubMap<K,V> extends AbstractMap<K,V>
-        implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+        implements ConcurrentNavigableMap<K,V>, Serializable {
         private static final long serialVersionUID = -7647078645895051609L;
 
         /** Underlying map */
@@ -2582,8 +2387,8 @@
 
         // Lazily initialized view holders
         private transient KeySet<K,V> keySetView;
-        private transient Set<Map.Entry<K,V>> entrySetView;
-        private transient Collection<V> valuesView;
+        private transient Values<K,V> valuesView;
+        private transient EntrySet<K,V> entrySetView;
 
         /**
          * Creates a new submap, initializing all fields.
@@ -2642,9 +2447,7 @@
             if (k == null) // pass by markers and headers
                 return true;
             int c = cpr(cmp, k, hi);
-            if (c > 0 || (c == 0 && !hiInclusive))
-                return false;
-            return true;
+            return c < 0 || (c == 0 && hiInclusive);
         }
 
         /**
@@ -2702,38 +2505,34 @@
         Map.Entry<K,V> lowestEntry() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
-                if (!isBeforeEnd(n, cmp))
+                ConcurrentSkipListMap.Node<K,V> n; V v;
+                if ((n = loNode(cmp)) == null || !isBeforeEnd(n, cmp))
                     return null;
-                Map.Entry<K,V> e = n.createSnapshot();
-                if (e != null)
-                    return e;
+                else if ((v = n.val) != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
             }
         }
 
         Map.Entry<K,V> highestEntry() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
-                if (n == null || !inBounds(n.key, cmp))
+                ConcurrentSkipListMap.Node<K,V> n; V v;
+                if ((n = hiNode(cmp)) == null || !inBounds(n.key, cmp))
                     return null;
-                Map.Entry<K,V> e = n.createSnapshot();
-                if (e != null)
-                    return e;
+                else if ((v = n.val) != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
             }
         }
 
         Map.Entry<K,V> removeLowest() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                Node<K,V> n = loNode(cmp);
-                if (n == null)
+                ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+                if ((n = loNode(cmp)) == null)
                     return null;
-                K k = n.key;
-                if (!inBounds(k, cmp))
+                else if (!inBounds((k = n.key), cmp))
                     return null;
-                V v = m.doRemove(k, null);
-                if (v != null)
+                else if ((v = m.doRemove(k, null)) != null)
                     return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
             }
         }
@@ -2741,20 +2540,18 @@
         Map.Entry<K,V> removeHighest() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                Node<K,V> n = hiNode(cmp);
-                if (n == null)
+                ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+                if ((n = hiNode(cmp)) == null)
                     return null;
-                K k = n.key;
-                if (!inBounds(k, cmp))
+                else if (!inBounds((k = n.key), cmp))
                     return null;
-                V v = m.doRemove(k, null);
-                if (v != null)
+                else if ((v = m.doRemove(k, null)) != null)
                     return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
             }
         }
 
         /**
-         * Submap version of ConcurrentSkipListMap.getNearEntry.
+         * Submap version of ConcurrentSkipListMap.findNearEntry.
          */
         Map.Entry<K,V> getNearEntry(K key, int rel) {
             Comparator<? super K> cmp = m.comparator;
@@ -2768,15 +2565,12 @@
                 return ((rel & LT) != 0) ? null : lowestEntry();
             if (tooHigh(key, cmp))
                 return ((rel & LT) != 0) ? highestEntry() : null;
-            for (;;) {
-                Node<K,V> n = m.findNear(key, rel, cmp);
-                if (n == null || !inBounds(n.key, cmp))
-                    return null;
-                K k = n.key;
-                V v = n.getValidValue();
-                if (v != null)
-                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
-            }
+            AbstractMap.SimpleImmutableEntry<K,V> e =
+                m.findNearEntry(key, rel, cmp);
+            if (e == null || !inBounds(e.getKey(), cmp))
+                return null;
+            else
+                return e;
         }
 
         // Almost the same as getNearEntry, except for keys
@@ -2811,10 +2605,8 @@
                 Node<K,V> n = m.findNear(key, rel, cmp);
                 if (n == null || !inBounds(n.key, cmp))
                     return null;
-                K k = n.key;
-                V v = n.getValidValue();
-                if (v != null)
-                    return k;
+                if (n.val != null)
+                    return n.key;
             }
         }
 
@@ -2845,7 +2637,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                if (n.getValidValue() != null)
+                if (n.val != null)
                     ++count;
             }
             return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
@@ -2863,7 +2655,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                V v = n.getValidValue();
+                V v = n.val;
                 if (v != null && value.equals(v))
                     return true;
             }
@@ -2875,7 +2667,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                if (n.getValidValue() != null)
+                if (n.val != null)
                     m.remove(n.key);
             }
         }
@@ -3049,23 +2841,27 @@
         /* ---------------- Submap Views -------------- */
 
         public NavigableSet<K> keySet() {
-            KeySet<K,V> ks = keySetView;
-            return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+            KeySet<K,V> ks;
+            if ((ks = keySetView) != null) return ks;
+            return keySetView = new KeySet<>(this);
         }
 
         public NavigableSet<K> navigableKeySet() {
-            KeySet<K,V> ks = keySetView;
-            return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+            KeySet<K,V> ks;
+            if ((ks = keySetView) != null) return ks;
+            return keySetView = new KeySet<>(this);
         }
 
         public Collection<V> values() {
-            Collection<V> vs = valuesView;
-            return (vs != null) ? vs : (valuesView = new Values<>(this));
+            Values<K,V> vs;
+            if ((vs = valuesView) != null) return vs;
+            return valuesView = new Values<>(this);
         }
 
         public Set<Map.Entry<K,V>> entrySet() {
-            Set<Map.Entry<K,V>> es = entrySetView;
-            return (es != null) ? es : (entrySetView = new EntrySet<K,V>(this));
+            EntrySet<K,V> es;
+            if ((es = entrySetView) != null) return es;
+            return entrySetView = new EntrySet<K,V>(this);
         }
 
         public NavigableSet<K> descendingKeySet() {
@@ -3085,19 +2881,18 @@
             V nextValue;
 
             SubMapIter() {
+                VarHandle.acquireFence();
                 Comparator<? super K> cmp = m.comparator;
                 for (;;) {
                     next = isDescending ? hiNode(cmp) : loNode(cmp);
                     if (next == null)
                         break;
-                    Object x = next.value;
-                    if (x != null && x != next) {
+                    V x = next.val;
+                    if (x != null) {
                         if (! inBounds(next.key, cmp))
                             next = null;
-                        else {
-                            @SuppressWarnings("unchecked") V vv = (V)x;
-                            nextValue = vv;
-                        }
+                        else
+                            nextValue = x;
                         break;
                     }
                 }
@@ -3123,14 +2918,12 @@
                     next = next.next;
                     if (next == null)
                         break;
-                    Object x = next.value;
-                    if (x != null && x != next) {
+                    V x = next.val;
+                    if (x != null) {
                         if (tooHigh(next.key, cmp))
                             next = null;
-                        else {
-                            @SuppressWarnings("unchecked") V vv = (V)x;
-                            nextValue = vv;
-                        }
+                        else
+                            nextValue = x;
                         break;
                     }
                 }
@@ -3142,14 +2935,12 @@
                     next = m.findNear(lastReturned.key, LT, cmp);
                     if (next == null)
                         break;
-                    Object x = next.value;
-                    if (x != null && x != next) {
+                    V x = next.val;
+                    if (x != null) {
                         if (tooLow(next.key, cmp))
                             next = null;
-                        else {
-                            @SuppressWarnings("unchecked") V vv = (V)x;
-                            nextValue = vv;
-                        }
+                        else
+                            nextValue = x;
                         break;
                     }
                 }
@@ -3229,22 +3020,28 @@
 
     public void forEach(BiConsumer<? super K, ? super V> action) {
         if (action == null) throw new NullPointerException();
-        V v;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            if ((v = n.getValidValue()) != null)
-                action.accept(n.key, v);
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null)
+                    action.accept(n.key, v);
+                b = n;
+            }
         }
     }
 
     public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
         if (function == null) throw new NullPointerException();
-        V v;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            while ((v = n.getValidValue()) != null) {
-                V r = function.apply(n.key, v);
-                if (r == null) throw new NullPointerException();
-                if (n.casValue(v, r))
-                    break;
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                while ((v = n.val) != null) {
+                    V r = function.apply(n.key, v);
+                    if (r == null) throw new NullPointerException();
+                    if (VAL.compareAndSet(n, v, r))
+                        break;
+                }
+                b = n;
             }
         }
     }
@@ -3255,13 +3052,16 @@
     boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
         if (function == null) throw new NullPointerException();
         boolean removed = false;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            V v;
-            if ((v = n.getValidValue()) != null) {
-                K k = n.key;
-                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
-                if (function.test(e) && remove(k, v))
-                    removed = true;
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null) {
+                    K k = n.key;
+                    Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                    if (function.test(e) && remove(k, v))
+                        removed = true;
+                }
+                b = n;
             }
         }
         return removed;
@@ -3273,12 +3073,12 @@
     boolean removeValueIf(Predicate<? super V> function) {
         if (function == null) throw new NullPointerException();
         boolean removed = false;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            V v;
-            if ((v = n.getValidValue()) != null) {
-                K k = n.key;
-                if (function.test(v) && remove(k, v))
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null && function.test(v) && remove(n.key, v))
                     removed = true;
+                b = n;
             }
         }
         return removed;
@@ -3296,30 +3096,27 @@
      * off, or the end of row is encountered. Control of the number of
      * splits relies on some statistical estimation: The expected
      * remaining number of elements of a skip list when advancing
-     * either across or down decreases by about 25%. To make this
-     * observation useful, we need to know initial size, which we
-     * don't. But we can just use Integer.MAX_VALUE so that we
-     * don't prematurely zero out while splitting.
+     * either across or down decreases by about 25%.
      */
     abstract static class CSLMSpliterator<K,V> {
         final Comparator<? super K> comparator;
         final K fence;     // exclusive upper bound for keys, or null if to end
         Index<K,V> row;    // the level to split out
         Node<K,V> current; // current traversal node; initialize at origin
-        int est;           // pseudo-size estimate
+        long est;          // size estimate
         CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                        Node<K,V> origin, K fence, int est) {
+                        Node<K,V> origin, K fence, long est) {
             this.comparator = comparator; this.row = row;
             this.current = origin; this.fence = fence; this.est = est;
         }
 
-        public final long estimateSize() { return (long)est; }
+        public final long estimateSize() { return est; }
     }
 
     static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<K> {
         KeySpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                       Node<K,V> origin, K fence, int est) {
+                       Node<K,V> origin, K fence, long est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3331,7 +3128,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.value != null &&
+                        (n = b.next) != null && n.val != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3352,10 +3149,10 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if ((v = e.value) != null && v != e)
+                if (e.val != null)
                     action.accept(k);
             }
         }
@@ -3366,12 +3163,12 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if ((v = e.value) != null && v != e) {
+                if (e.val != null) {
                     current = e.next;
                     action.accept(k);
                     return true;
@@ -3393,21 +3190,23 @@
     }
     // factory method for KeySpliterator
     final KeySpliterator<K,V> keySpliterator() {
-        Comparator<? super K> cmp = comparator;
-        for (;;) { // ensure h corresponds to origin p
-            HeadIndex<K,V> h; Node<K,V> p;
-            Node<K,V> b = (h = head).node;
-            if ((p = b.next) == null || p.value != null)
-                return new KeySpliterator<K,V>(cmp, h, p, null, (p == null) ?
-                                               0 : Integer.MAX_VALUE);
-            p.helpDelete(b, p.next);
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
         }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new KeySpliterator<K,V>(comparator, h, n, null, est);
     }
 
     static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<V> {
         ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                       Node<K,V> origin, K fence, int est) {
+                       Node<K,V> origin, K fence, long est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3419,7 +3218,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.value != null &&
+                        (n = b.next) != null && n.val != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3440,13 +3239,11 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k; V v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if ((v = e.value) != null && v != e) {
-                    @SuppressWarnings("unchecked") V vv = (V)v;
-                    action.accept(vv);
-                }
+                if ((v = e.val) != null)
+                    action.accept(v);
             }
         }
 
@@ -3456,15 +3253,14 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k; V v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if ((v = e.value) != null && v != e) {
+                if ((v = e.val) != null) {
                     current = e.next;
-                    @SuppressWarnings("unchecked") V vv = (V)v;
-                    action.accept(vv);
+                    action.accept(v);
                     return true;
                 }
             }
@@ -3480,21 +3276,23 @@
 
     // Almost the same as keySpliterator()
     final ValueSpliterator<K,V> valueSpliterator() {
-        Comparator<? super K> cmp = comparator;
-        for (;;) {
-            HeadIndex<K,V> h; Node<K,V> p;
-            Node<K,V> b = (h = head).node;
-            if ((p = b.next) == null || p.value != null)
-                return new ValueSpliterator<K,V>(cmp, h, p, null, (p == null) ?
-                                                 0 : Integer.MAX_VALUE);
-            p.helpDelete(b, p.next);
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
         }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new ValueSpliterator<K,V>(comparator, h, n, null, est);
     }
 
     static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<Map.Entry<K,V>> {
         EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                         Node<K,V> origin, K fence, int est) {
+                         Node<K,V> origin, K fence, long est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3506,7 +3304,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.value != null &&
+                        (n = b.next) != null && n.val != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3527,13 +3325,12 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k; V v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if ((v = e.value) != null && v != e) {
-                    @SuppressWarnings("unchecked") V vv = (V)v;
+                if ((v = e.val) != null) {
                     action.accept
-                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
                 }
             }
         }
@@ -3544,16 +3341,15 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k; V v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if ((v = e.value) != null && v != e) {
+                if ((v = e.val) != null) {
                     current = e.next;
-                    @SuppressWarnings("unchecked") V vv = (V)v;
                     action.accept
-                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
                     return true;
                 }
             }
@@ -3584,26 +3380,37 @@
 
     // Almost the same as keySpliterator()
     final EntrySpliterator<K,V> entrySpliterator() {
-        Comparator<? super K> cmp = comparator;
-        for (;;) { // almost same as key version
-            HeadIndex<K,V> h; Node<K,V> p;
-            Node<K,V> b = (h = head).node;
-            if ((p = b.next) == null || p.value != null)
-                return new EntrySpliterator<K,V>(cmp, h, p, null, (p == null) ?
-                                                 0 : Integer.MAX_VALUE);
-            p.helpDelete(b, p.next);
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
         }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new EntrySpliterator<K,V>(comparator, h, n, null, est);
     }
 
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long HEAD;
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle ADDER;
+    private static final VarHandle NEXT;
+    private static final VarHandle VAL;
+    private static final VarHandle RIGHT;
     static {
         try {
-            HEAD = U.objectFieldOffset
-                (ConcurrentSkipListMap.class.getDeclaredField("head"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
+                                   Index.class);
+            ADDER = l.findVarHandle(ConcurrentSkipListMap.class, "adder",
+                                    LongAdder.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            VAL = l.findVarHandle(Node.class, "val", Object.class);
+            RIGHT = l.findVarHandle(Index.class, "right", Index.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
index 2e11b17..140bde4 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
@@ -35,23 +35,18 @@
 
 package java.util.concurrent;
 
+import java.lang.reflect.Field;
 import java.util.AbstractSet;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.NavigableMap;
 import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.Spliterator;
 
-// BEGIN android-note
-// removed link to collections framework docs
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
 /**
  * A scalable concurrent {@link NavigableSet} implementation based on
  * a {@link ConcurrentSkipListMap}.  The elements of the set are kept
@@ -75,12 +70,12 @@
  * asynchronous nature of these sets, determining the current number
  * of elements requires a traversal of the elements, and so may report
  * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code addAll},
- * {@code removeAll}, {@code retainAll}, {@code containsAll},
- * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
- * to be performed atomically. For example, an iterator operating
- * concurrently with an {@code addAll} operation might view only some
- * of the added elements.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe only some of the added elements.
  *
  * <p>This class and its iterators implement all of the
  * <em>optional</em> methods of the {@link Set} and {@link Iterator}
@@ -89,6 +84,10 @@
  * because {@code null} arguments and return values cannot be reliably
  * distinguished from the absence of elements.
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @author Doug Lea
  * @param <E> the type of elements maintained by this set
  * @since 1.6
@@ -310,9 +309,7 @@
         Collection<?> c = (Collection<?>) o;
         try {
             return containsAll(c) && c.containsAll(this);
-        } catch (ClassCastException unused) {
-            return false;
-        } catch (NullPointerException unused) {
+        } catch (ClassCastException | NullPointerException unused) {
             return false;
         }
     }
@@ -327,7 +324,7 @@
      * @return {@code true} if this set changed as a result of the call
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified collection or any
      *         of its elements are null
      */
@@ -491,9 +488,9 @@
      * encounter order that is ascending order.  Overriding implementations
      * should document the reporting of additional characteristic values.
      *
-     * <p>The spliterator's comparator (see
-     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
-     * the set's comparator (see {@link #comparator()}) is {@code null}.
+     * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
+     * is {@code null} if the {@linkplain #comparator() set's comparator}
+     * is {@code null}.
      * Otherwise, the spliterator's comparator is the same as or imposes the
      * same total ordering as the set's comparator.
      *
@@ -506,18 +503,21 @@
             : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
     }
 
-    // Support for resetting map in clone
+    /** Initializes map field; for use in clone. */
     private void setMap(ConcurrentNavigableMap<E,Object> map) {
-        U.putObjectVolatile(this, MAP, map);
-    }
-
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long MAP;
-    static {
+        Field mapField = java.security.AccessController.doPrivileged(
+            (java.security.PrivilegedAction<Field>) () -> {
+                try {
+                    Field f = ConcurrentSkipListSet.class
+                        .getDeclaredField("m");
+                    f.setAccessible(true);
+                    return f;
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }});
         try {
-            MAP = U.objectFieldOffset
-                (ConcurrentSkipListSet.class.getDeclaredField("m"));
-        } catch (ReflectiveOperationException e) {
+            mapField.set(this, map);
+        } catch (IllegalAccessException e) {
             throw new Error(e);
         }
     }
diff --git a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
index ebcbbef..912204f 100644
--- a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
@@ -34,7 +34,8 @@
 
 package java.util.concurrent;
 
-import java.util.AbstractList;
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
@@ -50,6 +51,7 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.UnaryOperator;
+import jdk.internal.misc.SharedSecrets;
 
 // Android-changed: Removed javadoc link to collections framework docs
 /**
@@ -81,6 +83,10 @@
  * actions subsequent to the access or removal of that element from
  * the {@code CopyOnWriteArrayList} in another thread.
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <E> the type of elements held in this list
@@ -129,17 +135,17 @@
      * @throws NullPointerException if the specified collection is null
      */
     public CopyOnWriteArrayList(Collection<? extends E> c) {
-        Object[] elements;
+        Object[] es;
         if (c.getClass() == CopyOnWriteArrayList.class)
-            elements = ((CopyOnWriteArrayList<?>)c).getArray();
+            es = ((CopyOnWriteArrayList<?>)c).getArray();
         else {
-            elements = c.toArray();
+            es = c.toArray();
             // defend against c.toArray (incorrectly) not returning Object[]
             // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
-            if (elements.getClass() != Object[].class)
-                elements = Arrays.copyOf(elements, elements.length, Object[].class);
+            if (es.getClass() != Object[].class)
+                es = Arrays.copyOf(es, es.length, Object[].class);
         }
-        setArray(elements);
+        setArray(es);
     }
 
     /**
@@ -175,20 +181,19 @@
      * static version of indexOf, to allow repeated calls without
      * needing to re-acquire array each time.
      * @param o element to search for
-     * @param elements the array
-     * @param index first index to search
-     * @param fence one past last index to search
+     * @param es the array
+     * @param from first index to search
+     * @param to one past last index to search
      * @return index of element, or -1 if absent
      */
-    private static int indexOf(Object o, Object[] elements,
-                               int index, int fence) {
+    private static int indexOfRange(Object o, Object[] es, int from, int to) {
         if (o == null) {
-            for (int i = index; i < fence; i++)
-                if (elements[i] == null)
+            for (int i = from; i < to; i++)
+                if (es[i] == null)
                     return i;
         } else {
-            for (int i = index; i < fence; i++)
-                if (o.equals(elements[i]))
+            for (int i = from; i < to; i++)
+                if (o.equals(es[i]))
                     return i;
         }
         return -1;
@@ -197,18 +202,19 @@
     /**
      * static version of lastIndexOf.
      * @param o element to search for
-     * @param elements the array
-     * @param index first index to search
+     * @param es the array
+     * @param from index of first element of range, last element to search
+     * @param to one past last element of range, first element to search
      * @return index of element, or -1 if absent
      */
-    private static int lastIndexOf(Object o, Object[] elements, int index) {
+    private static int lastIndexOfRange(Object o, Object[] es, int from, int to) {
         if (o == null) {
-            for (int i = index; i >= 0; i--)
-                if (elements[i] == null)
+            for (int i = to - 1; i >= from; i--)
+                if (es[i] == null)
                     return i;
         } else {
-            for (int i = index; i >= 0; i--)
-                if (o.equals(elements[i]))
+            for (int i = to - 1; i >= from; i--)
+                if (o.equals(es[i]))
                     return i;
         }
         return -1;
@@ -223,16 +229,15 @@
      * @return {@code true} if this list contains the specified element
      */
     public boolean contains(Object o) {
-        Object[] elements = getArray();
-        return indexOf(o, elements, 0, elements.length) >= 0;
+        return indexOf(o) >= 0;
     }
 
     /**
      * {@inheritDoc}
      */
     public int indexOf(Object o) {
-        Object[] elements = getArray();
-        return indexOf(o, elements, 0, elements.length);
+        Object[] es = getArray();
+        return indexOfRange(o, es, 0, es.length);
     }
 
     /**
@@ -251,16 +256,16 @@
      * @throws IndexOutOfBoundsException if the specified index is negative
      */
     public int indexOf(E e, int index) {
-        Object[] elements = getArray();
-        return indexOf(e, elements, index, elements.length);
+        Object[] es = getArray();
+        return indexOfRange(e, es, index, es.length);
     }
 
     /**
      * {@inheritDoc}
      */
     public int lastIndexOf(Object o) {
-        Object[] elements = getArray();
-        return lastIndexOf(o, elements, elements.length - 1);
+        Object[] es = getArray();
+        return lastIndexOfRange(o, es, 0, es.length);
     }
 
     /**
@@ -280,8 +285,8 @@
      *         than or equal to the current size of this list
      */
     public int lastIndexOf(E e, int index) {
-        Object[] elements = getArray();
-        return lastIndexOf(e, elements, index);
+        Object[] es = getArray();
+        return lastIndexOfRange(e, es, 0, index + 1);
     }
 
     /**
@@ -296,6 +301,9 @@
             CopyOnWriteArrayList<E> clone =
                 (CopyOnWriteArrayList<E>) super.clone();
             clone.resetLock();
+            // Unlike in readObject, here we cannot visibility-piggyback on the
+            // volatile write in setArray().
+            VarHandle.releaseFence();
             return clone;
         } catch (CloneNotSupportedException e) {
             // this shouldn't happen, since we are Cloneable
@@ -317,8 +325,7 @@
      * @return an array containing all the elements in this list
      */
     public Object[] toArray() {
-        Object[] elements = getArray();
-        return Arrays.copyOf(elements, elements.length);
+        return getArray().clone();
     }
 
     /**
@@ -361,12 +368,12 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        Object[] elements = getArray();
-        int len = elements.length;
+        Object[] es = getArray();
+        int len = es.length;
         if (a.length < len)
-            return (T[]) Arrays.copyOf(elements, len, a.getClass());
+            return (T[]) Arrays.copyOf(es, len, a.getClass());
         else {
-            System.arraycopy(elements, 0, a, 0, len);
+            System.arraycopy(es, 0, a, 0, len);
             if (a.length > len)
                 a[len] = null;
             return a;
@@ -376,7 +383,7 @@
     // Positional Access Operations
 
     @SuppressWarnings("unchecked")
-    private E get(Object[] a, int index) {
+    static <E> E elementAt(Object[] a, int index) {
         return (E) a[index];
     }
 
@@ -390,7 +397,7 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public E get(int index) {
-        return get(getArray(), index);
+        return elementAt(getArray(), index);
     }
 
     /**
@@ -401,17 +408,13 @@
      */
     public E set(int index, E element) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            E oldValue = get(elements, index);
+            Object[] es = getArray();
+            E oldValue = elementAt(es, index);
 
             if (oldValue != element) {
-                int len = elements.length;
-                Object[] newElements = Arrays.copyOf(elements, len);
-                newElements[index] = element;
-                setArray(newElements);
-            } else {
-                // Not quite a no-op; ensures volatile write semantics
-                setArray(elements);
+                es = es.clone();
+                es[index] = element;
+                setArray(es);
             }
             return oldValue;
         }
@@ -425,11 +428,11 @@
      */
     public boolean add(E e) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            Object[] newElements = Arrays.copyOf(elements, len + 1);
-            newElements[len] = e;
-            setArray(newElements);
+            Object[] es = getArray();
+            int len = es.length;
+            es = Arrays.copyOf(es, len + 1);
+            es[len] = e;
+            setArray(es);
             return true;
         }
     }
@@ -443,18 +446,18 @@
      */
     public void add(int index, E element) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
             if (index > len || index < 0)
                 throw new IndexOutOfBoundsException(outOfBounds(index, len));
             Object[] newElements;
             int numMoved = len - index;
             if (numMoved == 0)
-                newElements = Arrays.copyOf(elements, len + 1);
+                newElements = Arrays.copyOf(es, len + 1);
             else {
                 newElements = new Object[len + 1];
-                System.arraycopy(elements, 0, newElements, 0, index);
-                System.arraycopy(elements, index, newElements, index + 1,
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index, newElements, index + 1,
                                  numMoved);
             }
             newElements[index] = element;
@@ -471,19 +474,20 @@
      */
     public E remove(int index) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            E oldValue = get(elements, index);
+            Object[] es = getArray();
+            int len = es.length;
+            E oldValue = elementAt(es, index);
             int numMoved = len - index - 1;
+            Object[] newElements;
             if (numMoved == 0)
-                setArray(Arrays.copyOf(elements, len - 1));
+                newElements = Arrays.copyOf(es, len - 1);
             else {
-                Object[] newElements = new Object[len - 1];
-                System.arraycopy(elements, 0, newElements, 0, index);
-                System.arraycopy(elements, index + 1, newElements, index,
+                newElements = new Object[len - 1];
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index + 1, newElements, index,
                                  numMoved);
-                setArray(newElements);
             }
+            setArray(newElements);
             return oldValue;
         }
     }
@@ -502,8 +506,8 @@
      */
     public boolean remove(Object o) {
         Object[] snapshot = getArray();
-        int index = indexOf(o, snapshot, 0, snapshot.length);
-        return (index < 0) ? false : remove(o, snapshot, index);
+        int index = indexOfRange(o, snapshot, 0, snapshot.length);
+        return index >= 0 && remove(o, snapshot, index);
     }
 
     /**
@@ -527,7 +531,7 @@
                     return false;
                 if (current[index] == o)
                     break findIndex;
-                index = indexOf(o, current, index, len);
+                index = indexOfRange(o, current, index, len);
                 if (index < 0)
                     return false;
             }
@@ -555,19 +559,19 @@
      */
     void removeRange(int fromIndex, int toIndex) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
 
             if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
                 throw new IndexOutOfBoundsException();
             int newlen = len - (toIndex - fromIndex);
             int numMoved = len - toIndex;
             if (numMoved == 0)
-                setArray(Arrays.copyOf(elements, newlen));
+                setArray(Arrays.copyOf(es, newlen));
             else {
                 Object[] newElements = new Object[newlen];
-                System.arraycopy(elements, 0, newElements, 0, fromIndex);
-                System.arraycopy(elements, toIndex, newElements,
+                System.arraycopy(es, 0, newElements, 0, fromIndex);
+                System.arraycopy(es, toIndex, newElements,
                                  fromIndex, numMoved);
                 setArray(newElements);
             }
@@ -582,8 +586,8 @@
      */
     public boolean addIfAbsent(E e) {
         Object[] snapshot = getArray();
-        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
-            addIfAbsent(e, snapshot);
+        return indexOfRange(e, snapshot, 0, snapshot.length) < 0
+            && addIfAbsent(e, snapshot);
     }
 
     /**
@@ -601,7 +605,7 @@
                     if (current[i] != snapshot[i]
                         && Objects.equals(e, current[i]))
                         return false;
-                if (indexOf(e, current, common, len) >= 0)
+                if (indexOfRange(e, current, common, len) >= 0)
                         return false;
             }
             Object[] newElements = Arrays.copyOf(current, len + 1);
@@ -622,10 +626,10 @@
      * @see #contains(Object)
      */
     public boolean containsAll(Collection<?> c) {
-        Object[] elements = getArray();
-        int len = elements.length;
+        Object[] es = getArray();
+        int len = es.length;
         for (Object e : c) {
-            if (indexOf(e, elements, 0, len) < 0)
+            if (indexOfRange(e, es, 0, len) < 0)
                 return false;
         }
         return true;
@@ -640,34 +644,16 @@
      * @return {@code true} if this list changed as a result of the call
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this list contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
     public boolean removeAll(Collection<?> c) {
-        if (c == null) throw new NullPointerException();
-        synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            if (len != 0) {
-                // temp array holds those elements we know we want to keep
-                int newlen = 0;
-                Object[] temp = new Object[len];
-                for (int i = 0; i < len; ++i) {
-                    Object element = elements[i];
-                    if (!c.contains(element))
-                        temp[newlen++] = element;
-                }
-                if (newlen != len) {
-                    setArray(Arrays.copyOf(temp, newlen));
-                    return true;
-                }
-            }
-            return false;
-        }
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
     }
 
     /**
@@ -679,34 +665,16 @@
      * @return {@code true} if this list changed as a result of the call
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this list contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
     public boolean retainAll(Collection<?> c) {
-        if (c == null) throw new NullPointerException();
-        synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            if (len != 0) {
-                // temp array holds those elements we know we want to keep
-                int newlen = 0;
-                Object[] temp = new Object[len];
-                for (int i = 0; i < len; ++i) {
-                    Object element = elements[i];
-                    if (c.contains(element))
-                        temp[newlen++] = element;
-                }
-                if (newlen != len) {
-                    setArray(Arrays.copyOf(temp, newlen));
-                    return true;
-                }
-            }
-            return false;
-        }
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
     }
 
     /**
@@ -725,18 +693,18 @@
         if (cs.length == 0)
             return 0;
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
             int added = 0;
             // uniquify and compact elements in cs
             for (int i = 0; i < cs.length; ++i) {
                 Object e = cs[i];
-                if (indexOf(e, elements, 0, len) < 0 &&
-                    indexOf(e, cs, 0, added) < 0)
+                if (indexOfRange(e, es, 0, len) < 0 &&
+                    indexOfRange(e, cs, 0, added) < 0)
                     cs[added++] = e;
             }
             if (added > 0) {
-                Object[] newElements = Arrays.copyOf(elements, len + added);
+                Object[] newElements = Arrays.copyOf(es, len + added);
                 System.arraycopy(cs, 0, newElements, len, added);
                 setArray(newElements);
             }
@@ -770,15 +738,16 @@
         if (cs.length == 0)
             return false;
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
+            Object[] newElements;
             if (len == 0 && cs.getClass() == Object[].class)
-                setArray(cs);
+                newElements = cs;
             else {
-                Object[] newElements = Arrays.copyOf(elements, len + cs.length);
+                newElements = Arrays.copyOf(es, len + cs.length);
                 System.arraycopy(cs, 0, newElements, len, cs.length);
-                setArray(newElements);
             }
+            setArray(newElements);
             return true;
         }
     }
@@ -802,8 +771,8 @@
     public boolean addAll(int index, Collection<? extends E> c) {
         Object[] cs = c.toArray();
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
             if (index > len || index < 0)
                 throw new IndexOutOfBoundsException(outOfBounds(index, len));
             if (cs.length == 0)
@@ -811,11 +780,11 @@
             int numMoved = len - index;
             Object[] newElements;
             if (numMoved == 0)
-                newElements = Arrays.copyOf(elements, len + cs.length);
+                newElements = Arrays.copyOf(es, len + cs.length);
             else {
                 newElements = new Object[len + cs.length];
-                System.arraycopy(elements, 0, newElements, 0, index);
-                System.arraycopy(elements, index,
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index,
                                  newElements, index + cs.length,
                                  numMoved);
             }
@@ -825,65 +794,106 @@
         }
     }
 
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
     public void forEach(Consumer<? super E> action) {
-        if (action == null) throw new NullPointerException();
+        Objects.requireNonNull(action);
         for (Object x : getArray()) {
             @SuppressWarnings("unchecked") E e = (E) x;
             action.accept(e);
         }
     }
 
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
     public boolean removeIf(Predicate<? super E> filter) {
-        if (filter == null) throw new NullPointerException();
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    private boolean bulkRemove(Predicate<? super E> filter) {
         synchronized (lock) {
-            final Object[] elements = getArray();
-            final int len = elements.length;
-            int i;
-            for (i = 0; i < len; i++) {
-                @SuppressWarnings("unchecked") E e = (E) elements[i];
-                if (filter.test(e)) {
-                    int newlen = i;
-                    final Object[] newElements = new Object[len - 1];
-                    System.arraycopy(elements, 0, newElements, 0, newlen);
-                    for (i++; i < len; i++) {
-                        @SuppressWarnings("unchecked") E x = (E) elements[i];
-                        if (!filter.test(x))
-                            newElements[newlen++] = x;
-                    }
-                    setArray((newlen == len - 1)
-                             ? newElements // one match => one copy
-                             : Arrays.copyOf(newElements, newlen));
-                    return true;
+            return bulkRemove(filter, 0, getArray().length);
+        }
+    }
+
+    boolean bulkRemove(Predicate<? super E> filter, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray();
+        // Optimize for initial run of survivors
+        for (; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            int deleted = 1;
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i))) {
+                    setBit(deathRow, i - beg);
+                    deleted++;
                 }
-            }
-            return false;       // zero matches => zero copies
+            // Did filter reentrantly modify the list?
+            if (es != getArray())
+                throw new ConcurrentModificationException();
+            final Object[] newElts = Arrays.copyOf(es, es.length - deleted);
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    newElts[w++] = es[i];
+            System.arraycopy(es, i, newElts, w, es.length - i);
+            setArray(newElts);
+            return true;
+        } else {
+            if (es != getArray())
+                throw new ConcurrentModificationException();
+            return false;
         }
     }
 
     public void replaceAll(UnaryOperator<E> operator) {
-        if (operator == null) throw new NullPointerException();
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            Object[] newElements = Arrays.copyOf(elements, len);
-            for (int i = 0; i < len; ++i) {
-                @SuppressWarnings("unchecked") E e = (E) elements[i];
-                newElements[i] = operator.apply(e);
-            }
-            setArray(newElements);
+            replaceAllRange(operator, 0, getArray().length);
         }
     }
 
+    void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        Objects.requireNonNull(operator);
+        final Object[] es = getArray().clone();
+        for (; i < end; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        setArray(es);
+    }
+
     public void sort(Comparator<? super E> c) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            Object[] newElements = Arrays.copyOf(elements, elements.length);
-            @SuppressWarnings("unchecked") E[] es = (E[])newElements;
-            Arrays.sort(es, c);
-            setArray(newElements);
+            sortRange(c, 0, getArray().length);
         }
     }
 
+    @SuppressWarnings("unchecked")
+    void sortRange(Comparator<? super E> c, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray().clone();
+        Arrays.sort(es, i, end, (Comparator<Object>)c);
+        setArray(es);
+    }
+
     /**
      * Saves this list to a stream (that is, serializes it).
      *
@@ -898,12 +908,12 @@
 
         s.defaultWriteObject();
 
-        Object[] elements = getArray();
+        Object[] es = getArray();
         // Write out array length
-        s.writeInt(elements.length);
+        s.writeInt(es.length);
 
         // Write out all elements in the proper order.
-        for (Object element : elements)
+        for (Object element : es)
             s.writeObject(element);
     }
 
@@ -924,12 +934,13 @@
 
         // Read in array length and allocate array
         int len = s.readInt();
-        Object[] elements = new Object[len];
+        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len);
+        Object[] es = new Object[len];
 
         // Read in all elements in the proper order.
         for (int i = 0; i < len; i++)
-            elements[i] = s.readObject();
-        setArray(elements);
+            es[i] = s.readObject();
+        setArray(es);
     }
 
     /**
@@ -969,13 +980,19 @@
 
         List<?> list = (List<?>)o;
         Iterator<?> it = list.iterator();
-        Object[] elements = getArray();
-        for (int i = 0, len = elements.length; i < len; i++)
-            if (!it.hasNext() || !Objects.equals(elements[i], it.next()))
+        for (Object element : getArray())
+            if (!it.hasNext() || !Objects.equals(element, it.next()))
                 return false;
-        if (it.hasNext())
-            return false;
-        return true;
+        return !it.hasNext();
+    }
+
+    private static int hashCodeOfRange(Object[] es, int from, int to) {
+        int hashCode = 1;
+        for (int i = from; i < to; i++) {
+            Object x = es[i];
+            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
+        }
+        return hashCode;
     }
 
     /**
@@ -986,10 +1003,8 @@
      * @return the hash code value for this list
      */
     public int hashCode() {
-        int hashCode = 1;
-        for (Object x : getArray())
-            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
-        return hashCode;
+        Object[] es = getArray();
+        return hashCodeOfRange(es, 0, es.length);
     }
 
     /**
@@ -1029,12 +1044,12 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public ListIterator<E> listIterator(int index) {
-        Object[] elements = getArray();
-        int len = elements.length;
+        Object[] es = getArray();
+        int len = es.length;
         if (index < 0 || index > len)
             throw new IndexOutOfBoundsException(outOfBounds(index, len));
 
-        return new COWIterator<E>(elements, index);
+        return new COWIterator<E>(es, index);
     }
 
     /**
@@ -1062,9 +1077,9 @@
         /** Index of element to be returned by subsequent call to next.  */
         private int cursor;
 
-        COWIterator(Object[] elements, int initialCursor) {
+        COWIterator(Object[] es, int initialCursor) {
             cursor = initialCursor;
-            snapshot = elements;
+            snapshot = es;
         }
 
         public boolean hasNext() {
@@ -1094,7 +1109,7 @@
         }
 
         public int previousIndex() {
-            return cursor-1;
+            return cursor - 1;
         }
 
         /**
@@ -1125,14 +1140,13 @@
         }
 
         @Override
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
             Objects.requireNonNull(action);
             final int size = snapshot.length;
-            for (int i = cursor; i < size; i++) {
-                action.accept((E) snapshot[i]);
-            }
+            int i = cursor;
             cursor = size;
+            for (; i < size; i++)
+                action.accept(elementAt(snapshot, i));
         }
     }
 
@@ -1153,324 +1167,358 @@
      */
     public List<E> subList(int fromIndex, int toIndex) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
+            Object[] es = getArray();
+            int len = es.length;
+            int size = toIndex - fromIndex;
+            if (fromIndex < 0 || toIndex > len || size < 0)
                 throw new IndexOutOfBoundsException();
-            return new COWSubList<E>(this, fromIndex, toIndex);
+            return new COWSubList(es, fromIndex, size);
         }
     }
 
     /**
      * Sublist for CopyOnWriteArrayList.
-     * This class extends AbstractList merely for convenience, to
-     * avoid having to define addAll, etc. This doesn't hurt, but
-     * is wasteful.  This class does not need or use modCount
-     * mechanics in AbstractList, but does need to check for
-     * concurrent modification using similar mechanics.  On each
-     * operation, the array that we expect the backing list to use
-     * is checked and updated.  Since we do this for all of the
-     * base operations invoked by those defined in AbstractList,
-     * all is well.  While inefficient, this is not worth
-     * improving.  The kinds of list operations inherited from
-     * AbstractList are already so slow on COW sublists that
-     * adding a bit more space/time doesn't seem even noticeable.
      */
-    private static class COWSubList<E>
-        extends AbstractList<E>
-        implements RandomAccess
-    {
-        private final CopyOnWriteArrayList<E> l;
+    private class COWSubList implements List<E>, RandomAccess {
         private final int offset;
         private int size;
         private Object[] expectedArray;
 
-        // only call this holding l's lock
-        COWSubList(CopyOnWriteArrayList<E> list,
-                   int fromIndex, int toIndex) {
-            // assert Thread.holdsLock(list.lock);
-            l = list;
-            expectedArray = l.getArray();
-            offset = fromIndex;
-            size = toIndex - fromIndex;
+        COWSubList(Object[] es, int offset, int size) {
+            // assert Thread.holdsLock(lock);
+            expectedArray = es;
+            this.offset = offset;
+            this.size = size;
         }
 
-        // only call this holding l's lock
         private void checkForComodification() {
-            // assert Thread.holdsLock(l.lock);
-            if (l.getArray() != expectedArray)
+            // assert Thread.holdsLock(lock);
+            if (getArray() != expectedArray)
                 throw new ConcurrentModificationException();
         }
 
-        // only call this holding l's lock
+        private Object[] getArrayChecked() {
+            // assert Thread.holdsLock(lock);
+            Object[] a = getArray();
+            if (a != expectedArray)
+                throw new ConcurrentModificationException();
+            return a;
+        }
+
         private void rangeCheck(int index) {
-            // assert Thread.holdsLock(l.lock);
+            // assert Thread.holdsLock(lock);
             if (index < 0 || index >= size)
                 throw new IndexOutOfBoundsException(outOfBounds(index, size));
         }
 
+        private void rangeCheckForAdd(int index) {
+            // assert Thread.holdsLock(lock);
+            if (index < 0 || index > size)
+                throw new IndexOutOfBoundsException(outOfBounds(index, size));
+        }
+
+        public Object[] toArray() {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            return Arrays.copyOfRange(es, offset, offset + size);
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            if (a.length < size)
+                return (T[]) Arrays.copyOfRange(
+                        es, offset, offset + size, a.getClass());
+            else {
+                System.arraycopy(es, offset, a, 0, size);
+                if (a.length > size)
+                    a[size] = null;
+                return a;
+            }
+        }
+
+        public int indexOf(Object o) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            int i = indexOfRange(o, es, offset, offset + size);
+            return (i == -1) ? -1 : i - offset;
+        }
+
+        public int lastIndexOf(Object o) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            int i = lastIndexOfRange(o, es, offset, offset + size);
+            return (i == -1) ? -1 : i - offset;
+        }
+
+        public boolean contains(Object o) {
+            return indexOf(o) >= 0;
+        }
+
+        public boolean containsAll(Collection<?> c) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            for (Object o : c)
+                if (indexOfRange(o, es, offset, offset + size) < 0)
+                    return false;
+            return true;
+        }
+
+        public boolean isEmpty() {
+            return size() == 0;
+        }
+
+        public String toString() {
+            return Arrays.toString(toArray());
+        }
+
+        public int hashCode() {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            return hashCodeOfRange(es, offset, offset + size);
+        }
+
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof List))
+                return false;
+            Iterator<?> it = ((List<?>)o).iterator();
+
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+
+            for (int i = offset, end = offset + size; i < end; i++)
+                if (!it.hasNext() || !Objects.equals(es[i], it.next()))
+                    return false;
+            return !it.hasNext();
+        }
+
         public E set(int index, E element) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E x = l.set(index+offset, element);
-                expectedArray = l.getArray();
+                E x = CopyOnWriteArrayList.this.set(offset + index, element);
+                expectedArray = getArray();
                 return x;
             }
         }
 
         public E get(int index) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 rangeCheck(index);
                 checkForComodification();
-                return l.get(index+offset);
+                return CopyOnWriteArrayList.this.get(offset + index);
             }
         }
 
         public int size() {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
                 return size;
             }
         }
 
-        public void add(int index, E element) {
-            synchronized (l.lock) {
+        public boolean add(E element) {
+            synchronized (lock) {
                 checkForComodification();
-                if (index < 0 || index > size)
-                    throw new IndexOutOfBoundsException
-                        (outOfBounds(index, size));
-                l.add(index+offset, element);
-                expectedArray = l.getArray();
+                CopyOnWriteArrayList.this.add(offset + size, element);
+                expectedArray = getArray();
+                size++;
+            }
+            return true;
+        }
+
+        public void add(int index, E element) {
+            synchronized (lock) {
+                checkForComodification();
+                rangeCheckForAdd(index);
+                CopyOnWriteArrayList.this.add(offset + index, element);
+                expectedArray = getArray();
                 size++;
             }
         }
 
+        public boolean addAll(Collection<? extends E> c) {
+            synchronized (lock) {
+                final Object[] oldArray = getArrayChecked();
+                boolean modified =
+                    CopyOnWriteArrayList.this.addAll(offset + size, c);
+                size += (expectedArray = getArray()).length - oldArray.length;
+                return modified;
+            }
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            synchronized (lock) {
+                rangeCheckForAdd(index);
+                final Object[] oldArray = getArrayChecked();
+                boolean modified =
+                    CopyOnWriteArrayList.this.addAll(offset + index, c);
+                size += (expectedArray = getArray()).length - oldArray.length;
+                return modified;
+            }
+        }
+
         public void clear() {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                l.removeRange(offset, offset+size);
-                expectedArray = l.getArray();
+                removeRange(offset, offset + size);
+                expectedArray = getArray();
                 size = 0;
             }
         }
 
         public E remove(int index) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E result = l.remove(index+offset);
-                expectedArray = l.getArray();
+                E result = CopyOnWriteArrayList.this.remove(offset + index);
+                expectedArray = getArray();
                 size--;
                 return result;
             }
         }
 
         public boolean remove(Object o) {
-            int index = indexOf(o);
-            if (index == -1)
-                return false;
-            remove(index);
-            return true;
-        }
-
-        public Iterator<E> iterator() {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                return new COWSubListIterator<E>(l, 0, offset, size);
+                int index = indexOf(o);
+                if (index == -1)
+                    return false;
+                remove(index);
+                return true;
             }
         }
 
+        public Iterator<E> iterator() {
+            return listIterator(0);
+        }
+
+        public ListIterator<E> listIterator() {
+            return listIterator(0);
+        }
+
         public ListIterator<E> listIterator(int index) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                if (index < 0 || index > size)
-                    throw new IndexOutOfBoundsException
-                        (outOfBounds(index, size));
-                return new COWSubListIterator<E>(l, index, offset, size);
+                rangeCheckForAdd(index);
+                return new COWSubListIterator<E>(
+                    CopyOnWriteArrayList.this, index, offset, size);
             }
         }
 
         public List<E> subList(int fromIndex, int toIndex) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
                 if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
                     throw new IndexOutOfBoundsException();
-                return new COWSubList<E>(l, fromIndex + offset,
-                                         toIndex + offset);
+                return new COWSubList(expectedArray, fromIndex + offset, toIndex - fromIndex);
             }
         }
 
         public void forEach(Consumer<? super E> action) {
-            if (action == null) throw new NullPointerException();
-            int lo = offset;
-            int hi = offset + size;
-            Object[] a = expectedArray;
-            if (l.getArray() != a)
-                throw new ConcurrentModificationException();
-            if (lo < 0 || hi > a.length)
-                throw new IndexOutOfBoundsException();
-            for (int i = lo; i < hi; ++i) {
-                @SuppressWarnings("unchecked") E e = (E) a[i];
-                action.accept(e);
+            Objects.requireNonNull(action);
+            int i, end; final Object[] es;
+            synchronized (lock) {
+                es = getArrayChecked();
+                i = offset;
+                end = i + size;
             }
+            for (; i < end; i++)
+                action.accept(elementAt(es, i));
         }
 
         public void replaceAll(UnaryOperator<E> operator) {
-            if (operator == null) throw new NullPointerException();
-            synchronized (l.lock) {
-                int lo = offset;
-                int hi = offset + size;
-                Object[] elements = expectedArray;
-                if (l.getArray() != elements)
-                    throw new ConcurrentModificationException();
-                int len = elements.length;
-                if (lo < 0 || hi > len)
-                    throw new IndexOutOfBoundsException();
-                Object[] newElements = Arrays.copyOf(elements, len);
-                for (int i = lo; i < hi; ++i) {
-                    @SuppressWarnings("unchecked") E e = (E) elements[i];
-                    newElements[i] = operator.apply(e);
-                }
-                l.setArray(expectedArray = newElements);
+            synchronized (lock) {
+                checkForComodification();
+                replaceAllRange(operator, offset, offset + size);
+                expectedArray = getArray();
             }
         }
 
         public void sort(Comparator<? super E> c) {
-            synchronized (l.lock) {
-                int lo = offset;
-                int hi = offset + size;
-                Object[] elements = expectedArray;
-                if (l.getArray() != elements)
-                    throw new ConcurrentModificationException();
-                int len = elements.length;
-                if (lo < 0 || hi > len)
-                    throw new IndexOutOfBoundsException();
-                Object[] newElements = Arrays.copyOf(elements, len);
-                @SuppressWarnings("unchecked") E[] es = (E[])newElements;
-                Arrays.sort(es, lo, hi, c);
-                l.setArray(expectedArray = newElements);
+            synchronized (lock) {
+                checkForComodification();
+                sortRange(c, offset, offset + size);
+                expectedArray = getArray();
             }
         }
 
         public boolean removeAll(Collection<?> c) {
-            if (c == null) throw new NullPointerException();
-            boolean removed = false;
-            synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        Object element = elements[i];
-                        if (!c.contains(element))
-                            temp[newSize++] = element;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
-            }
-            return removed;
+            Objects.requireNonNull(c);
+            return bulkRemove(e -> c.contains(e));
         }
 
         public boolean retainAll(Collection<?> c) {
-            if (c == null) throw new NullPointerException();
-            boolean removed = false;
-            synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        Object element = elements[i];
-                        if (c.contains(element))
-                            temp[newSize++] = element;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
-            }
-            return removed;
+            Objects.requireNonNull(c);
+            return bulkRemove(e -> !c.contains(e));
         }
 
         public boolean removeIf(Predicate<? super E> filter) {
-            if (filter == null) throw new NullPointerException();
-            boolean removed = false;
-            synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        @SuppressWarnings("unchecked") E e = (E) elements[i];
-                        if (!filter.test(e))
-                            temp[newSize++] = e;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
+            Objects.requireNonNull(filter);
+            return bulkRemove(filter);
+        }
+
+        private boolean bulkRemove(Predicate<? super E> filter) {
+            synchronized (lock) {
+                final Object[] oldArray = getArrayChecked();
+                boolean modified = CopyOnWriteArrayList.this.bulkRemove(
+                    filter, offset, offset + size);
+                size += (expectedArray = getArray()).length - oldArray.length;
+                return modified;
             }
-            return removed;
         }
 
         public Spliterator<E> spliterator() {
-            int lo = offset;
-            int hi = offset + size;
-            Object[] a = expectedArray;
-            if (l.getArray() != a)
-                throw new ConcurrentModificationException();
-            if (lo < 0 || hi > a.length)
-                throw new IndexOutOfBoundsException();
-            return Spliterators.spliterator
-                (a, lo, hi, Spliterator.IMMUTABLE | Spliterator.ORDERED);
+            synchronized (lock) {
+                return Spliterators.spliterator(
+                        getArrayChecked(), offset, offset + size,
+                        Spliterator.IMMUTABLE | Spliterator.ORDERED);
+            }
         }
 
     }
@@ -1483,7 +1531,7 @@
         COWSubListIterator(List<E> l, int index, int offset, int size) {
             this.offset = offset;
             this.size = size;
-            it = l.listIterator(index+offset);
+            it = l.listIterator(index + offset);
         }
 
         public boolean hasNext() {
@@ -1532,23 +1580,27 @@
         @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
             Objects.requireNonNull(action);
-            while (nextIndex() < size) {
+            while (hasNext()) {
                 action.accept(it.next());
             }
         }
     }
 
-    // Support for resetting lock while deserializing
+    /** Initializes the lock; for use when deserializing or cloning. */
     private void resetLock() {
-        U.putObjectVolatile(this, LOCK, new Object());
-    }
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long LOCK;
-    static {
+        Field lockField = java.security.AccessController.doPrivileged(
+            (java.security.PrivilegedAction<Field>) () -> {
+                try {
+                    Field f = CopyOnWriteArrayList.class
+                        .getDeclaredField("lock");
+                    f.setAccessible(true);
+                    return f;
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }});
         try {
-            LOCK = U.objectFieldOffset
-                (CopyOnWriteArrayList.class.getDeclaredField("lock"));
-        } catch (ReflectiveOperationException e) {
+            lockField.set(this, new Object());
+        } catch (IllegalAccessException e) {
             throw new Error(e);
         }
     }
diff --git a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
index fb707dd..b14a3e8 100644
--- a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
+++ b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
@@ -45,13 +45,8 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
-// BEGIN android-note
-// removed link to collections framework docs
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
 /**
- * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
+ * A {@link Set} that uses an internal {@link CopyOnWriteArrayList}
  * for all of its operations.  Thus, it shares the same basic properties:
  * <ul>
  *  <li>It is best suited for applications in which set sizes generally
@@ -91,6 +86,10 @@
  *   }
  * }}</pre>
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @see CopyOnWriteArrayList
  * @since 1.5
  * @author Doug Lea
@@ -341,10 +340,10 @@
      * @return {@code true} if this set changed as a result of the call
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this set contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
@@ -364,10 +363,10 @@
      * @return {@code true} if this set changed as a result of the call
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
-     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this set contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
@@ -412,10 +411,16 @@
                 && compareSets(al.getArray(), (Set<?>) o) == 0);
     }
 
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
     public boolean removeIf(Predicate<? super E> filter) {
         return al.removeIf(filter);
     }
 
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
     public void forEach(Consumer<? super E> action) {
         al.forEach(action);
     }
diff --git a/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java b/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
index a29208e..a91d12d 100644
--- a/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
+++ b/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
@@ -35,6 +35,9 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
 /**
  * A {@link ForkJoinTask} with a completion action performed when
  * triggered and there are no remaining pending actions.
@@ -54,8 +57,7 @@
  * decremented; otherwise, the completion action is performed, and if
  * this completer itself has a completer, the process is continued
  * with its completer.  As is the case with related synchronization
- * components such as {@link java.util.concurrent.Phaser Phaser} and
- * {@link java.util.concurrent.Semaphore Semaphore}, these methods
+ * components such as {@link Phaser} and {@link Semaphore}, these methods
  * affect only internal counts; they do not establish any further
  * internal bookkeeping. In particular, the identities of pending
  * tasks are not maintained. As illustrated below, you can create
@@ -117,102 +119,114 @@
  * to complete for some elements than others, either because of
  * intrinsic variation (for example I/O) or auxiliary effects such as
  * garbage collection.  Because CountedCompleters provide their own
- * continuations, other threads need not block waiting to perform
- * them.
+ * continuations, other tasks need not block waiting to perform them.
  *
- * <p>For example, here is an initial version of a class that uses
- * divide-by-two recursive decomposition to divide work into single
- * pieces (leaf tasks). Even when work is split into individual calls,
- * tree-based techniques are usually preferable to directly forking
- * leaf tasks, because they reduce inter-thread communication and
- * improve load balancing. In the recursive case, the second of each
- * pair of subtasks to finish triggers completion of its parent
+ * <p>For example, here is an initial version of a utility method that
+ * uses divide-by-two recursive decomposition to divide work into
+ * single pieces (leaf tasks). Even when work is split into individual
+ * calls, tree-based techniques are usually preferable to directly
+ * forking leaf tasks, because they reduce inter-thread communication
+ * and improve load balancing. In the recursive case, the second of
+ * each pair of subtasks to finish triggers completion of their parent
  * (because no result combination is performed, the default no-op
  * implementation of method {@code onCompletion} is not overridden).
- * A static utility method sets up the base task and invokes it
- * (here, implicitly using the {@link ForkJoinPool#commonPool()}).
+ * The utility method sets up the root task and invokes it (here,
+ * implicitly using the {@link ForkJoinPool#commonPool()}).  It is
+ * straightforward and reliable (but not optimal) to always set the
+ * pending count to the number of child tasks and call {@code
+ * tryComplete()} immediately before returning.
  *
  * <pre> {@code
- * class MyOperation<E> { void apply(E e) { ... }  }
- *
- * class ForEach<E> extends CountedCompleter<Void> {
- *
- *   public static <E> void forEach(E[] array, MyOperation<E> op) {
- *     new ForEach<E>(null, array, op, 0, array.length).invoke();
- *   }
- *
- *   final E[] array; final MyOperation<E> op; final int lo, hi;
- *   ForEach(CountedCompleter<?> p, E[] array, MyOperation<E> op, int lo, int hi) {
- *     super(p);
- *     this.array = array; this.op = op; this.lo = lo; this.hi = hi;
- *   }
- *
- *   public void compute() { // version 1
- *     if (hi - lo >= 2) {
- *       int mid = (lo + hi) >>> 1;
- *       setPendingCount(2); // must set pending count before fork
- *       new ForEach(this, array, op, mid, hi).fork(); // right child
- *       new ForEach(this, array, op, lo, mid).fork(); // left child
+ * public static <E> void forEach(E[] array, Consumer<E> action) {
+ *   class Task extends CountedCompleter<Void> {
+ *     final int lo, hi;
+ *     Task(Task parent, int lo, int hi) {
+ *       super(parent); this.lo = lo; this.hi = hi;
  *     }
- *     else if (hi > lo)
- *       op.apply(array[lo]);
- *     tryComplete();
+ *
+ *     public void compute() {
+ *       if (hi - lo >= 2) {
+ *         int mid = (lo + hi) >>> 1;
+ *         // must set pending count before fork
+ *         setPendingCount(2);
+ *         new Task(this, mid, hi).fork(); // right child
+ *         new Task(this, lo, mid).fork(); // left child
+ *       }
+ *       else if (hi > lo)
+ *         action.accept(array[lo]);
+ *       tryComplete();
+ *     }
  *   }
+ *   new Task(null, 0, array.length).invoke();
  * }}</pre>
  *
  * This design can be improved by noticing that in the recursive case,
  * the task has nothing to do after forking its right task, so can
  * directly invoke its left task before returning. (This is an analog
- * of tail recursion removal.)  Also, because the task returns upon
- * executing its left task (rather than falling through to invoke
- * {@code tryComplete}) the pending count is set to one:
+ * of tail recursion removal.)  Also, when the last action in a task
+ * is to fork or invoke a subtask (a "tail call"), the call to {@code
+ * tryComplete()} can be optimized away, at the cost of making the
+ * pending count look "off by one".
  *
  * <pre> {@code
- * class ForEach<E> ... {
- *   ...
- *   public void compute() { // version 2
- *     if (hi - lo >= 2) {
- *       int mid = (lo + hi) >>> 1;
- *       setPendingCount(1); // only one pending
- *       new ForEach(this, array, op, mid, hi).fork(); // right child
- *       new ForEach(this, array, op, lo, mid).compute(); // direct invoke
- *     }
- *     else {
- *       if (hi > lo)
- *         op.apply(array[lo]);
- *       tryComplete();
- *     }
- *   }
- * }}</pre>
+ *     public void compute() {
+ *       if (hi - lo >= 2) {
+ *         int mid = (lo + hi) >>> 1;
+ *         setPendingCount(1); // looks off by one, but correct!
+ *         new Task(this, mid, hi).fork(); // right child
+ *         new Task(this, lo, mid).compute(); // direct invoke
+ *       } else {
+ *         if (hi > lo)
+ *           action.accept(array[lo]);
+ *         tryComplete();
+ *       }
+ *     }}</pre>
  *
  * As a further optimization, notice that the left task need not even exist.
- * Instead of creating a new one, we can iterate using the original task,
+ * Instead of creating a new one, we can continue using the original task,
  * and add a pending count for each fork.  Additionally, because no task
  * in this tree implements an {@link #onCompletion(CountedCompleter)} method,
- * {@code tryComplete()} can be replaced with {@link #propagateCompletion}.
+ * {@code tryComplete} can be replaced with {@link #propagateCompletion}.
  *
  * <pre> {@code
- * class ForEach<E> ... {
- *   ...
- *   public void compute() { // version 3
- *     int l = lo, h = hi;
- *     while (h - l >= 2) {
- *       int mid = (l + h) >>> 1;
- *       addToPendingCount(1);
- *       new ForEach(this, array, op, mid, h).fork(); // right child
- *       h = mid;
+ *     public void compute() {
+ *       int n = hi - lo;
+ *       for (; n >= 2; n /= 2) {
+ *         addToPendingCount(1);
+ *         new Task(this, lo + n/2, lo + n).fork();
+ *       }
+ *       if (n > 0)
+ *         action.accept(array[lo]);
+ *       propagateCompletion();
+ *     }}</pre>
+ *
+ * When pending counts can be precomputed, they can be established in
+ * the constructor:
+ *
+ * <pre> {@code
+ * public static <E> void forEach(E[] array, Consumer<E> action) {
+ *   class Task extends CountedCompleter<Void> {
+ *     final int lo, hi;
+ *     Task(Task parent, int lo, int hi) {
+ *       super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
+ *       this.lo = lo; this.hi = hi;
  *     }
- *     if (h > l)
- *       op.apply(array[l]);
- *     propagateCompletion();
+ *
+ *     public void compute() {
+ *       for (int n = hi - lo; n >= 2; n /= 2)
+ *         new Task(this, lo + n/2, lo + n).fork();
+ *       action.accept(array[lo]);
+ *       propagateCompletion();
+ *     }
  *   }
+ *   if (array.length > 0)
+ *     new Task(null, 0, array.length).invoke();
  * }}</pre>
  *
- * Additional optimizations of such classes might entail precomputing
- * pending counts so that they can be established in constructors,
- * specializing classes for leaf steps, subdividing by say, four,
- * instead of two per iteration, and using an adaptive threshold
- * instead of always subdividing down to single elements.
+ * Additional optimizations of such classes might entail specializing
+ * classes for leaf steps, subdividing by say, four, instead of two
+ * per iteration, and using an adaptive threshold instead of always
+ * subdividing down to single elements.
  *
  * <p><b>Searching.</b> A tree of CountedCompleters can search for a
  * value or property in different parts of a data structure, and
@@ -524,7 +538,7 @@
      * @param delta the value to add
      */
     public final void addToPendingCount(int delta) {
-        U.getAndAddInt(this, PENDING, delta);
+        PENDING.getAndAdd(this, delta);
     }
 
     /**
@@ -536,7 +550,7 @@
      * @return {@code true} if successful
      */
     public final boolean compareAndSetPendingCount(int expected, int count) {
-        return U.compareAndSwapInt(this, PENDING, expected, count);
+        return PENDING.compareAndSet(this, expected, count);
     }
 
     /**
@@ -548,7 +562,7 @@
     public final int decrementPendingCountUnlessZero() {
         int c;
         do {} while ((c = pending) != 0 &&
-                     !U.compareAndSwapInt(this, PENDING, c, c - 1));
+                     !PENDING.weakCompareAndSet(this, c, c - 1));
         return c;
     }
 
@@ -581,7 +595,7 @@
                     return;
                 }
             }
-            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+            else if (PENDING.weakCompareAndSet(a, c, c - 1))
                 return;
         }
     }
@@ -596,7 +610,7 @@
      * not, be invoked for each completer in a computation.
      */
     public final void propagateCompletion() {
-        CountedCompleter<?> a = this, s = a;
+        CountedCompleter<?> a = this, s;
         for (int c;;) {
             if ((c = a.pending) == 0) {
                 if ((a = (s = a).completer) == null) {
@@ -604,7 +618,7 @@
                     return;
                 }
             }
-            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+            else if (PENDING.weakCompareAndSet(a, c, c - 1))
                 return;
         }
     }
@@ -649,7 +663,7 @@
         for (int c;;) {
             if ((c = pending) == 0)
                 return this;
-            else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
+            else if (PENDING.weakCompareAndSet(this, c, c - 1))
                 return null;
         }
     }
@@ -721,7 +735,7 @@
         CountedCompleter<?> a = this, s = a;
         while (a.onExceptionalCompletion(ex, s) &&
                (a = (s = a).completer) != null && a.status >= 0 &&
-               a.recordExceptionalCompletion(ex) == EXCEPTIONAL)
+               isExceptionalStatus(a.recordExceptionalCompletion(ex)))
             ;
     }
 
@@ -753,15 +767,15 @@
      */
     protected void setRawResult(T t) { }
 
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long PENDING;
+    // VarHandle mechanics
+    private static final VarHandle PENDING;
     static {
         try {
-            PENDING = U.objectFieldOffset
-                (CountedCompleter.class.getDeclaredField("pending"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
+
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java b/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
index 5e018f1..269bec4 100644
--- a/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
+++ b/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
@@ -82,8 +82,7 @@
  *   public Solver(float[][] matrix) {
  *     data = matrix;
  *     N = matrix.length;
- *     Runnable barrierAction =
- *       new Runnable() { public void run() { mergeRows(...); }};
+ *     Runnable barrierAction = () -> mergeRows(...);
  *     barrier = new CyclicBarrier(N, barrierAction);
  *
  *     List<Thread> threads = new ArrayList<>(N);
@@ -132,10 +131,10 @@
  * <i>happen-before</i> actions following a successful return from the
  * corresponding {@code await()} in other threads.
  *
- * @since 1.5
  * @see CountDownLatch
  *
  * @author Doug Lea
+ * @since 1.5
  */
 public class CyclicBarrier {
     /**
@@ -150,7 +149,8 @@
      * but no subsequent reset.
      */
     private static class Generation {
-        boolean broken;         // initially false
+        Generation() {}                 // prevent access constructor creation
+        boolean broken;                 // initially false
     }
 
     /** The lock for guarding barrier entry */
diff --git a/ojluni/src/main/java/java/util/concurrent/DelayQueue.java b/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
index 04a83d9..bf0858d 100644
--- a/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
@@ -41,14 +41,11 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.PriorityQueue;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
 /**
  * An unbounded {@linkplain BlockingQueue blocking queue} of
  * {@code Delayed} elements, in which an element can only be taken
@@ -63,11 +60,15 @@
  * returns the count of both expired and unexpired elements.
  * This queue does not permit null elements.
  *
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.  The Iterator provided in method {@link
- * #iterator()} is <em>not</em> guaranteed to traverse the elements of
- * the DelayQueue in any particular order.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ * The Iterator provided in method {@link #iterator()} is <em>not</em>
+ * guaranteed to traverse the elements of the DelayQueue in any
+ * particular order.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
  *
  * @since 1.5
  * @author Doug Lea
@@ -322,40 +323,13 @@
     }
 
     /**
-     * Returns first element only if it is expired.
-     * Used only by drainTo.  Call only when holding lock.
-     */
-    private E peekExpired() {
-        // assert lock.isHeldByCurrentThread();
-        E first = q.peek();
-        return (first == null || first.getDelay(NANOSECONDS) > 0) ?
-            null : first;
-    }
-
-    /**
      * @throws UnsupportedOperationException {@inheritDoc}
      * @throws ClassCastException            {@inheritDoc}
      * @throws NullPointerException          {@inheritDoc}
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c) {
-        if (c == null)
-            throw new NullPointerException();
-        if (c == this)
-            throw new IllegalArgumentException();
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try {
-            int n = 0;
-            for (E e; (e = peekExpired()) != null;) {
-                c.add(e);       // In this order, in case add() throws.
-                q.poll();
-                ++n;
-            }
-            return n;
-        } finally {
-            lock.unlock();
-        }
+        return drainTo(c, Integer.MAX_VALUE);
     }
 
     /**
@@ -365,8 +339,7 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        if (c == null)
-            throw new NullPointerException();
+        Objects.requireNonNull(c);
         if (c == this)
             throw new IllegalArgumentException();
         if (maxElements <= 0)
@@ -375,8 +348,11 @@
         lock.lock();
         try {
             int n = 0;
-            for (E e; n < maxElements && (e = peekExpired()) != null;) {
-                c.add(e);       // In this order, in case add() throws.
+            for (E first;
+                 n < maxElements
+                     && (first = q.peek()) != null
+                     && first.getDelay(NANOSECONDS) <= 0;) {
+                c.add(first);   // In this order, in case add() throws.
                 q.poll();
                 ++n;
             }
@@ -547,8 +523,7 @@
         public E next() {
             if (cursor >= array.length)
                 throw new NoSuchElementException();
-            lastRet = cursor;
-            return (E)array[cursor++];
+            return (E)array[lastRet = cursor++];
         }
 
         public void remove() {
diff --git a/ojluni/src/main/java/java/util/concurrent/Exchanger.java b/ojluni/src/main/java/java/util/concurrent/Exchanger.java
index f01a705..c55e5ac 100644
--- a/ojluni/src/main/java/java/util/concurrent/Exchanger.java
+++ b/ojluni/src/main/java/java/util/concurrent/Exchanger.java
@@ -36,6 +36,10 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.locks.LockSupport;
+
 /**
  * A synchronization point at which threads can pair and swap elements
  * within pairs.  Each thread presents some object on entry to the
@@ -155,9 +159,7 @@
      * a value that is enough for common platforms.  Additionally,
      * extra care elsewhere is taken to avoid other false/unintended
      * sharing and to enhance locality, including adding padding (via
-     * @Contended) to Nodes, embedding "bound" as an Exchanger field,
-     * and reworking some park/unpark mechanics compared to
-     * LockSupport versions.
+     * @Contended) to Nodes, embedding "bound" as an Exchanger field.
      *
      * The arena starts out with only one used slot. We expand the
      * effective arena size by tracking collisions; i.e., failed CASes
@@ -233,29 +235,23 @@
      * As is too common in this sort of code, methods are monolithic
      * because most of the logic relies on reads of fields that are
      * maintained as local variables so can't be nicely factored --
-     * mainly, here, bulky spin->yield->block/cancel code), and
-     * heavily dependent on intrinsics (Unsafe) to use inlined
-     * embedded CAS and related memory access operations (that tend
-     * not to be as readily inlined by dynamic compilers when they are
-     * hidden behind other methods that would more nicely name and
-     * encapsulate the intended effects). This includes the use of
-     * putOrderedX to clear fields of the per-thread Nodes between
-     * uses. Note that field Node.item is not declared as volatile
-     * even though it is read by releasing threads, because they only
-     * do so after CAS operations that must precede access, and all
-     * uses by the owning thread are otherwise acceptably ordered by
-     * other operations. (Because the actual points of atomicity are
-     * slot CASes, it would also be legal for the write to Node.match
-     * in a release to be weaker than a full volatile write. However,
-     * this is not done because it could allow further postponement of
-     * the write, delaying progress.)
+     * mainly, here, bulky spin->yield->block/cancel code.  Note that
+     * field Node.item is not declared as volatile even though it is
+     * read by releasing threads, because they only do so after CAS
+     * operations that must precede access, and all uses by the owning
+     * thread are otherwise acceptably ordered by other operations.
+     * (Because the actual points of atomicity are slot CASes, it
+     * would also be legal for the write to Node.match in a release to
+     * be weaker than a full volatile write. However, this is not done
+     * because it could allow further postponement of the write,
+     * delaying progress.)
      */
 
     /**
-     * The byte distance (as a shift value) between any two used slots
-     * in the arena.  1 << ASHIFT should be at least cacheline size.
+     * The index distance (as a shift value) between any two used slots
+     * in the arena, spacing them out to avoid false sharing.
      */
-    private static final int ASHIFT = 7;
+    private static final int ASHIFT = 5;
 
     /**
      * The maximum supported arena index. The maximum allocatable
@@ -306,8 +302,7 @@
      * Nodes hold partially exchanged data, plus other per-thread
      * bookkeeping. Padded via @Contended to reduce memory contention.
      */
-    // Android-removed: @Contended, this hint is not used by the Android runtime.
-    //@jdk.internal.vm.annotation.Contended
+    @jdk.internal.vm.annotation.Contended
     static final class Node {
         int index;              // Arena index
         int bound;              // Last recorded value of Exchanger.bound
@@ -358,27 +353,31 @@
      */
     private final Object arenaExchange(Object item, boolean timed, long ns) {
         Node[] a = arena;
+        int alen = a.length;
         Node p = participant.get();
         for (int i = p.index;;) {                      // access slot at i
-            int b, m, c; long j;                       // j is raw array offset
-            Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
-            if (q != null && U.compareAndSwapObject(a, j, q, null)) {
+            int b, m, c;
+            int j = (i << ASHIFT) + ((1 << ASHIFT) - 1);
+            if (j < 0 || j >= alen)
+                j = alen - 1;
+            Node q = (Node)AA.getAcquire(a, j);
+            if (q != null && AA.compareAndSet(a, j, q, null)) {
                 Object v = q.item;                     // release
                 q.match = item;
                 Thread w = q.parked;
                 if (w != null)
-                    U.unpark(w);
+                    LockSupport.unpark(w);
                 return v;
             }
             else if (i <= (m = (b = bound) & MMASK) && q == null) {
                 p.item = item;                         // offer
-                if (U.compareAndSwapObject(a, j, null, p)) {
+                if (AA.compareAndSet(a, j, null, p)) {
                     long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
                     Thread t = Thread.currentThread(); // wait
                     for (int h = p.hash, spins = SPINS;;) {
                         Object v = p.match;
                         if (v != null) {
-                            U.putOrderedObject(p, MATCH, null);
+                            MATCH.setRelease(p, null);
                             p.item = null;             // clear for next use
                             p.hash = h;
                             return v;
@@ -391,22 +390,24 @@
                                      (--spins & ((SPINS >>> 1) - 1)) == 0)
                                 Thread.yield();        // two yields per wait
                         }
-                        else if (U.getObjectVolatile(a, j) != p)
+                        else if (AA.getAcquire(a, j) != p)
                             spins = SPINS;       // releaser hasn't set match yet
                         else if (!t.isInterrupted() && m == 0 &&
                                  (!timed ||
                                   (ns = end - System.nanoTime()) > 0L)) {
-                            U.putObject(t, BLOCKER, this); // emulate LockSupport
                             p.parked = t;              // minimize window
-                            if (U.getObjectVolatile(a, j) == p)
-                                U.park(false, ns);
+                            if (AA.getAcquire(a, j) == p) {
+                                if (ns == 0L)
+                                    LockSupport.park(this);
+                                else
+                                    LockSupport.parkNanos(this, ns);
+                            }
                             p.parked = null;
-                            U.putObject(t, BLOCKER, null);
                         }
-                        else if (U.getObjectVolatile(a, j) == p &&
-                                 U.compareAndSwapObject(a, j, p, null)) {
+                        else if (AA.getAcquire(a, j) == p &&
+                                 AA.compareAndSet(a, j, p, null)) {
                             if (m != 0)                // try to shrink
-                                U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
+                                BOUND.compareAndSet(this, b, b + SEQ - 1);
                             p.item = null;
                             p.hash = h;
                             i = p.index >>>= 1;        // descend
@@ -428,7 +429,7 @@
                     i = (i != m || m == 0) ? m : m - 1;
                 }
                 else if ((c = p.collides) < m || m == FULL ||
-                         !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
+                         !BOUND.compareAndSet(this, b, b + SEQ + 1)) {
                     p.collides = c + 1;
                     i = (i == 0) ? m : i - 1;          // cyclically traverse
                 }
@@ -457,24 +458,24 @@
 
         for (Node q;;) {
             if ((q = slot) != null) {
-                if (U.compareAndSwapObject(this, SLOT, q, null)) {
+                if (SLOT.compareAndSet(this, q, null)) {
                     Object v = q.item;
                     q.match = item;
                     Thread w = q.parked;
                     if (w != null)
-                        U.unpark(w);
+                        LockSupport.unpark(w);
                     return v;
                 }
                 // create arena on contention, but continue until slot null
                 if (NCPU > 1 && bound == 0 &&
-                    U.compareAndSwapInt(this, BOUND, 0, SEQ))
+                    BOUND.compareAndSet(this, 0, SEQ))
                     arena = new Node[(FULL + 2) << ASHIFT];
             }
             else if (arena != null)
                 return null; // caller must reroute to arenaExchange
             else {
                 p.item = item;
-                if (U.compareAndSwapObject(this, SLOT, null, p))
+                if (SLOT.compareAndSet(this, null, p))
                     break;
                 p.item = null;
             }
@@ -497,19 +498,21 @@
                 spins = SPINS;
             else if (!t.isInterrupted() && arena == null &&
                      (!timed || (ns = end - System.nanoTime()) > 0L)) {
-                U.putObject(t, BLOCKER, this);
                 p.parked = t;
-                if (slot == p)
-                    U.park(false, ns);
+                if (slot == p) {
+                    if (ns == 0L)
+                        LockSupport.park(this);
+                    else
+                        LockSupport.parkNanos(this, ns);
+                }
                 p.parked = null;
-                U.putObject(t, BLOCKER, null);
             }
-            else if (U.compareAndSwapObject(this, SLOT, p, null)) {
+            else if (SLOT.compareAndSet(this, p, null)) {
                 v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
                 break;
             }
         }
-        U.putOrderedObject(p, MATCH, null);
+        MATCH.setRelease(p, null);
         p.item = null;
         p.hash = h;
         return v;
@@ -558,8 +561,9 @@
     @SuppressWarnings("unchecked")
     public V exchange(V x) throws InterruptedException {
         Object v;
+        Node[] a;
         Object item = (x == null) ? NULL_ITEM : x; // translate null args
-        if ((arena != null ||
+        if (((a = arena) != null ||
              (v = slotExchange(item, false, 0L)) == null) &&
             ((Thread.interrupted() || // disambiguates null return
               (v = arenaExchange(item, false, 0L)) == null)))
@@ -625,33 +629,20 @@
         return (v == NULL_ITEM) ? null : (V)v;
     }
 
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long BOUND;
-    private static final long SLOT;
-    private static final long MATCH;
-    private static final long BLOCKER;
-    private static final int ABASE;
+    // VarHandle mechanics
+    private static final VarHandle BOUND;
+    private static final VarHandle SLOT;
+    private static final VarHandle MATCH;
+    private static final VarHandle AA;
     static {
         try {
-            BOUND = U.objectFieldOffset
-                (Exchanger.class.getDeclaredField("bound"));
-            SLOT = U.objectFieldOffset
-                (Exchanger.class.getDeclaredField("slot"));
-
-            MATCH = U.objectFieldOffset
-                (Node.class.getDeclaredField("match"));
-
-            BLOCKER = U.objectFieldOffset
-                (Thread.class.getDeclaredField("parkBlocker"));
-
-            int scale = U.arrayIndexScale(Node[].class);
-            if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
-                throw new Error("Unsupported array scale");
-            // ABASE absorbs padding in front of element 0
-            ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            BOUND = l.findVarHandle(Exchanger.class, "bound", int.class);
+            SLOT = l.findVarHandle(Exchanger.class, "slot", Node.class);
+            MATCH = l.findVarHandle(Node.class, "match", Object.class);
+            AA = MethodHandles.arrayElementVarHandle(Node[].class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
diff --git a/ojluni/src/main/java/java/util/concurrent/Executor.java b/ojluni/src/main/java/java/util/concurrent/Executor.java
index a615705..378cacd 100644
--- a/ojluni/src/main/java/java/util/concurrent/Executor.java
+++ b/ojluni/src/main/java/java/util/concurrent/Executor.java
@@ -87,14 +87,12 @@
  *     this.executor = executor;
  *   }
  *
- *   public synchronized void execute(final Runnable r) {
- *     tasks.add(new Runnable() {
- *       public void run() {
- *         try {
- *           r.run();
- *         } finally {
- *           scheduleNext();
- *         }
+ *   public synchronized void execute(Runnable r) {
+ *     tasks.add(() -> {
+ *       try {
+ *         r.run();
+ *       } finally {
+ *         scheduleNext();
  *       }
  *     });
  *     if (active == null) {
diff --git a/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
index a093844..d60d3dd 100644
--- a/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
+++ b/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
@@ -56,13 +56,11 @@
  * void solve(Executor e,
  *            Collection<Callable<Result>> solvers)
  *     throws InterruptedException, ExecutionException {
- *   CompletionService<Result> ecs
- *       = new ExecutorCompletionService<Result>(e);
- *   for (Callable<Result> s : solvers)
- *     ecs.submit(s);
- *   int n = solvers.size();
- *   for (int i = 0; i < n; ++i) {
- *     Result r = ecs.take().get();
+ *   CompletionService<Result> cs
+ *       = new ExecutorCompletionService<>(e);
+ *   solvers.forEach(cs::submit);
+ *   for (int i = solvers.size(); i > 0; i--) {
+ *     Result r = cs.take().get();
  *     if (r != null)
  *       use(r);
  *   }
@@ -76,32 +74,31 @@
  * void solve(Executor e,
  *            Collection<Callable<Result>> solvers)
  *     throws InterruptedException {
- *   CompletionService<Result> ecs
- *       = new ExecutorCompletionService<Result>(e);
+ *   CompletionService<Result> cs
+ *       = new ExecutorCompletionService<>(e);
  *   int n = solvers.size();
  *   List<Future<Result>> futures = new ArrayList<>(n);
  *   Result result = null;
  *   try {
- *     for (Callable<Result> s : solvers)
- *       futures.add(ecs.submit(s));
- *     for (int i = 0; i < n; ++i) {
+ *     solvers.forEach(solver -> futures.add(cs.submit(solver)));
+ *     for (int i = n; i > 0; i--) {
  *       try {
- *         Result r = ecs.take().get();
+ *         Result r = cs.take().get();
  *         if (r != null) {
  *           result = r;
  *           break;
  *         }
  *       } catch (ExecutionException ignore) {}
  *     }
- *   }
- *   finally {
- *     for (Future<Result> f : futures)
- *       f.cancel(true);
+ *   } finally {
+ *     futures.forEach(future -> future.cancel(true));
  *   }
  *
  *   if (result != null)
  *     use(result);
  * }}</pre>
+ *
+ * @since 1.5
  */
 public class ExecutorCompletionService<V> implements CompletionService<V> {
     private final Executor executor;
@@ -177,6 +174,10 @@
         this.completionQueue = completionQueue;
     }
 
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
     public Future<V> submit(Callable<V> task) {
         if (task == null) throw new NullPointerException();
         RunnableFuture<V> f = newTaskFor(task);
@@ -184,6 +185,10 @@
         return f;
     }
 
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
     public Future<V> submit(Runnable task, V result) {
         if (task == null) throw new NullPointerException();
         RunnableFuture<V> f = newTaskFor(task, result);
diff --git a/ojluni/src/main/java/java/util/concurrent/Executors.java b/ojluni/src/main/java/java/util/concurrent/Executors.java
index 565fdeb..e8cc0c1 100644
--- a/ojluni/src/main/java/java/util/concurrent/Executors.java
+++ b/ojluni/src/main/java/java/util/concurrent/Executors.java
@@ -35,6 +35,7 @@
 
 package java.util.concurrent;
 
+import static java.lang.ref.Reference.reachabilityFence;
 import dalvik.annotation.optimization.ReachabilitySensitive;
 import java.security.AccessControlContext;
 import java.security.AccessControlException;
@@ -190,9 +191,7 @@
      * returned executor is guaranteed not to be reconfigurable to use
      * additional threads.
      *
-     * @param threadFactory the factory to use when creating new
-     * threads
-     *
+     * @param threadFactory the factory to use when creating new threads
      * @return the newly created single-threaded Executor
      * @throws NullPointerException if threadFactory is null
      */
@@ -231,6 +230,7 @@
      * will reuse previously constructed threads when they are
      * available, and uses the provided
      * ThreadFactory to create new threads when needed.
+     *
      * @param threadFactory the factory to use when creating new threads
      * @return the newly created thread pool
      * @throws NullPointerException if threadFactory is null
@@ -253,6 +253,7 @@
      * given time. Unlike the otherwise equivalent
      * {@code newScheduledThreadPool(1)} the returned executor is
      * guaranteed not to be reconfigurable to use additional threads.
+     *
      * @return the newly created scheduled executor
      */
     public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
@@ -271,9 +272,9 @@
      * equivalent {@code newScheduledThreadPool(1, threadFactory)}
      * the returned executor is guaranteed not to be reconfigurable to
      * use additional threads.
-     * @param threadFactory the factory to use when creating new
-     * threads
-     * @return a newly created scheduled executor
+     *
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created scheduled executor
      * @throws NullPointerException if threadFactory is null
      */
     public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
@@ -286,7 +287,7 @@
      * given delay, or to execute periodically.
      * @param corePoolSize the number of threads to keep in the pool,
      * even if they are idle
-     * @return a newly created scheduled thread pool
+     * @return the newly created scheduled thread pool
      * @throws IllegalArgumentException if {@code corePoolSize < 0}
      */
     public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
@@ -300,7 +301,7 @@
      * even if they are idle
      * @param threadFactory the factory to use when the executor
      * creates a new thread
-     * @return a newly created scheduled thread pool
+     * @return the newly created scheduled thread pool
      * @throws IllegalArgumentException if {@code corePoolSize < 0}
      * @throws NullPointerException if threadFactory is null
      */
@@ -462,6 +463,9 @@
             task.run();
             return result;
         }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
     }
 
     /**
@@ -488,6 +492,10 @@
                 throw e.getException();
             }
         }
+
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
     }
 
     /**
@@ -543,6 +551,10 @@
                 throw e.getException();
             }
         }
+
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
     }
 
     /**
@@ -604,7 +616,7 @@
         public Thread newThread(final Runnable r) {
             return super.newThread(new Runnable() {
                 public void run() {
-                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    AccessController.doPrivileged(new PrivilegedAction<>() {
                         public Void run() {
                             Thread.currentThread().setContextClassLoader(ccl);
                             r.run();
@@ -621,47 +633,79 @@
      * of an ExecutorService implementation.
      */
     private static class DelegatedExecutorService
-            extends AbstractExecutorService {
+            implements ExecutorService {
         // Android-added: @ReachabilitySensitive
         // Needed for FinalizableDelegatedExecutorService below.
         @ReachabilitySensitive
         private final ExecutorService e;
         DelegatedExecutorService(ExecutorService executor) { e = executor; }
-        public void execute(Runnable command) { e.execute(command); }
+        public void execute(Runnable command) {
+            try {
+                e.execute(command);
+            } finally { reachabilityFence(this); }
+        }
         public void shutdown() { e.shutdown(); }
-        public List<Runnable> shutdownNow() { return e.shutdownNow(); }
-        public boolean isShutdown() { return e.isShutdown(); }
-        public boolean isTerminated() { return e.isTerminated(); }
+        public List<Runnable> shutdownNow() {
+            try {
+                return e.shutdownNow();
+            } finally { reachabilityFence(this); }
+        }
+        public boolean isShutdown() {
+            try {
+                return e.isShutdown();
+            } finally { reachabilityFence(this); }
+        }
+        public boolean isTerminated() {
+            try {
+                return e.isTerminated();
+            } finally { reachabilityFence(this); }
+        }
         public boolean awaitTermination(long timeout, TimeUnit unit)
             throws InterruptedException {
-            return e.awaitTermination(timeout, unit);
+            try {
+                return e.awaitTermination(timeout, unit);
+            } finally { reachabilityFence(this); }
         }
         public Future<?> submit(Runnable task) {
-            return e.submit(task);
+            try {
+                return e.submit(task);
+            } finally { reachabilityFence(this); }
         }
         public <T> Future<T> submit(Callable<T> task) {
-            return e.submit(task);
+            try {
+                return e.submit(task);
+            } finally { reachabilityFence(this); }
         }
         public <T> Future<T> submit(Runnable task, T result) {
-            return e.submit(task, result);
+            try {
+                return e.submit(task, result);
+            } finally { reachabilityFence(this); }
         }
         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
             throws InterruptedException {
-            return e.invokeAll(tasks);
+            try {
+                return e.invokeAll(tasks);
+            } finally { reachabilityFence(this); }
         }
         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                              long timeout, TimeUnit unit)
             throws InterruptedException {
-            return e.invokeAll(tasks, timeout, unit);
+            try {
+                return e.invokeAll(tasks, timeout, unit);
+            } finally { reachabilityFence(this); }
         }
         public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
             throws InterruptedException, ExecutionException {
-            return e.invokeAny(tasks);
+            try {
+                return e.invokeAny(tasks);
+            } finally { reachabilityFence(this); }
         }
         public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                                long timeout, TimeUnit unit)
             throws InterruptedException, ExecutionException, TimeoutException {
-            return e.invokeAny(tasks, timeout, unit);
+            try {
+                return e.invokeAny(tasks, timeout, unit);
+            } finally { reachabilityFence(this); }
         }
     }
 
@@ -670,6 +714,7 @@
         FinalizableDelegatedExecutorService(ExecutorService executor) {
             super(executor);
         }
+        @SuppressWarnings("deprecation")
         protected void finalize() {
             super.shutdown();
         }
diff --git a/ojluni/src/main/java/java/util/concurrent/Flow.java b/ojluni/src/main/java/java/util/concurrent/Flow.java
index 0231790..727a507 100644
--- a/ojluni/src/main/java/java/util/concurrent/Flow.java
+++ b/ojluni/src/main/java/java/util/concurrent/Flow.java
@@ -85,9 +85,9 @@
  *       this.executor = executor;
  *     }
  *     public synchronized void request(long n) {
- *       if (n != 0 && !completed) {
+ *       if (!completed) {
  *         completed = true;
- *         if (n < 0) {
+ *         if (n <= 0) {
  *           IllegalArgumentException ex = new IllegalArgumentException();
  *           executor.execute(() -> subscriber.onError(ex));
  *         } else {
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
index 04ad7d7..109a63c 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -36,15 +36,19 @@
 package java.util.concurrent;
 
 import java.lang.Thread.UncaughtExceptionHandler;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.security.AccessController;
 import java.security.AccessControlContext;
+import java.security.Permission;
 import java.security.Permissions;
+import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Predicate;
 import java.util.concurrent.locks.LockSupport;
 
 /**
@@ -63,7 +67,8 @@
  * tasks are submitted to the pool from external clients.  Especially
  * when setting <em>asyncMode</em> to true in constructors, {@code
  * ForkJoinPool}s may also be appropriate for use with event-style
- * tasks that are never joined.
+ * tasks that are never joined. All worker threads are initialized
+ * with {@link Thread#isDaemon} set {@code true}.
  *
  * <p>A static {@link #commonPool()} is available and appropriate for
  * most applications. The common pool is used by any ForkJoinTask that
@@ -81,7 +86,9 @@
  * However, no such adjustments are guaranteed in the face of blocked
  * I/O or other unmanaged synchronization. The nested {@link
  * ManagedBlocker} interface enables extension of the kinds of
- * synchronization accommodated.
+ * synchronization accommodated. The default policies may be
+ * overridden using a constructor with parameters corresponding to
+ * those documented in class {@link ThreadPoolExecutor}.
  *
  * <p>In addition to execution and lifecycle control methods, this
  * class provides status check methods (for example
@@ -102,48 +109,54 @@
  * async event-style tasks that are not usually joined, in which case
  * there is little difference among choice of methods.
  *
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <table class="plain">
  * <caption>Summary of task execution methods</caption>
  *  <tr>
  *    <td></td>
- *    <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td>
- *    <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td>
+ *    <th scope="col"> Call from non-fork/join clients</th>
+ *    <th scope="col"> Call from within fork/join computations</th>
  *  </tr>
  *  <tr>
- *    <td> <b>Arrange async execution</b></td>
+ *    <th scope="row" style="text-align:left"> Arrange async execution</th>
  *    <td> {@link #execute(ForkJoinTask)}</td>
  *    <td> {@link ForkJoinTask#fork}</td>
  *  </tr>
  *  <tr>
- *    <td> <b>Await and obtain result</b></td>
+ *    <th scope="row" style="text-align:left"> Await and obtain result</th>
  *    <td> {@link #invoke(ForkJoinTask)}</td>
  *    <td> {@link ForkJoinTask#invoke}</td>
  *  </tr>
  *  <tr>
- *    <td> <b>Arrange exec and obtain Future</b></td>
+ *    <th scope="row" style="text-align:left"> Arrange exec and obtain Future</th>
  *    <td> {@link #submit(ForkJoinTask)}</td>
  *    <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
  *  </tr>
  * </table>
  *
- * <p>The common pool is by default constructed with default
- * parameters, but these may be controlled by setting three
- * {@linkplain System#getProperty system properties}:
+ * <p>The parameters used to construct the common pool may be controlled by
+ * setting the following {@linkplain System#getProperty system properties}:
  * <ul>
  * <li>{@code java.util.concurrent.ForkJoinPool.common.parallelism}
  * - the parallelism level, a non-negative integer
  * <li>{@code java.util.concurrent.ForkJoinPool.common.threadFactory}
- * - the class name of a {@link ForkJoinWorkerThreadFactory}
+ * - the class name of a {@link ForkJoinWorkerThreadFactory}.
+ * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
+ * is used to load this class.
  * <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler}
- * - the class name of a {@link UncaughtExceptionHandler}
+ * - the class name of a {@link UncaughtExceptionHandler}.
+ * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
+ * is used to load this class.
  * <li>{@code java.util.concurrent.ForkJoinPool.common.maximumSpares}
  * - the maximum number of allowed extra threads to maintain target
  * parallelism (default 256).
  * </ul>
- * If a {@link SecurityManager} is present and no factory is
- * specified, then the default pool uses a factory supplying
- * threads that have no {@link Permissions} enabled.
- * The system class loader is used to load these classes.
+ * If no thread factory is supplied via a system property, then the
+ * common pool uses a factory that uses the system class loader as the
+ * {@linkplain Thread#getContextClassLoader() thread context class loader}.
+ * In addition, if a {@link SecurityManager} is present, then
+ * the common pool uses a factory supplying threads that have no
+ * {@link Permissions} enabled.
+ *
  * Upon any error in establishing these settings, default parameters
  * are used. It is possible to disable or limit the use of threads in
  * the common pool by setting the parallelism property to zero, and/or
@@ -162,8 +175,7 @@
  * @since 1.7
  * @author Doug Lea
  */
-// Android-removed: @Contended, this hint is not used by the Android runtime.
-//@jdk.internal.vm.annotation.Contended
+@jdk.internal.vm.annotation.Contended
 public class ForkJoinPool extends AbstractExecutorService {
 
     /*
@@ -173,17 +185,22 @@
      * functionality and control for a set of worker threads:
      * Submissions from non-FJ threads enter into submission queues.
      * Workers take these tasks and typically split them into subtasks
-     * that may be stolen by other workers.  Preference rules give
-     * first priority to processing tasks from their own queues (LIFO
-     * or FIFO, depending on mode), then to randomized FIFO steals of
-     * tasks in other queues.  This framework began as vehicle for
-     * supporting tree-structured parallelism using work-stealing.
-     * Over time, its scalability advantages led to extensions and
-     * changes to better support more diverse usage contexts.  Because
-     * most internal methods and nested classes are interrelated,
-     * their main rationale and descriptions are presented here;
-     * individual methods and nested classes contain only brief
-     * comments about details.
+     * that may be stolen by other workers. Work-stealing based on
+     * randomized scans generally leads to better throughput than
+     * "work dealing" in which producers assign tasks to idle threads,
+     * in part because threads that have finished other tasks before
+     * the signalled thread wakes up (which can be a long time) can
+     * take the task instead.  Preference rules give first priority to
+     * processing tasks from their own queues (LIFO or FIFO, depending
+     * on mode), then to randomized FIFO steals of tasks in other
+     * queues.  This framework began as vehicle for supporting
+     * tree-structured parallelism using work-stealing.  Over time,
+     * its scalability advantages led to extensions and changes to
+     * better support more diverse usage contexts.  Because most
+     * internal methods and nested classes are interrelated, their
+     * main rationale and descriptions are presented here; individual
+     * methods and nested classes contain only brief comments about
+     * details.
      *
      * WorkQueues
      * ==========
@@ -216,9 +233,10 @@
      *
      * (The actual code needs to null-check and size-check the array,
      * uses masking, not mod, for indexing a power-of-two-sized array,
-     * properly fences accesses, and possibly signals waiting workers
-     * to start scanning -- see below.)  Both a successful pop and
-     * poll mainly entail a CAS of a slot from non-null to null.
+     * adds a release fence for publication, and possibly signals
+     * waiting workers to start scanning -- see below.)  Both a
+     * successful pop and poll mainly entail a CAS of a slot from
+     * non-null to null.
      *
      * The pop operation (always performed by owner) is:
      *   if ((the task at top slot is not null) and
@@ -230,10 +248,14 @@
      *        (CAS slot to null))
      *           increment base and return task;
      *
-     * There are several variants of each of these; for example most
-     * versions of poll pre-screen the CAS by rechecking that the base
-     * has not changed since reading the slot, and most methods only
-     * attempt the CAS if base appears not to be equal to top.
+     * There are several variants of each of these. Most uses occur
+     * within operations that also interleave contention or emptiness
+     * tracking or inspection of elements before extracting them, so
+     * must interleave these with the above code. When performed by
+     * owner, getAndSet is used instead of CAS (see for example method
+     * nextLocalTask) which is usually more efficient, and possible
+     * because the top index cannot independently change during the
+     * operation.
      *
      * Memory ordering.  See "Correct and Efficient Work-Stealing for
      * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
@@ -242,33 +264,37 @@
      * algorithms similar to (but different than) the one used here.
      * Extracting tasks in array slots via (fully fenced) CAS provides
      * primary synchronization. The base and top indices imprecisely
-     * guide where to extract from. We do not always require strict
-     * orderings of array and index updates, so sometimes let them be
-     * subject to compiler and processor reorderings. However, the
-     * volatile "base" index also serves as a basis for memory
-     * ordering: Slot accesses are preceded by a read of base,
-     * ensuring happens-before ordering with respect to stealers (so
-     * the slots themselves can be read via plain array reads.)  The
-     * only other memory orderings relied on are maintained in the
-     * course of signalling and activation (see below).  A check that
-     * base == top indicates (momentary) emptiness, but otherwise may
-     * err on the side of possibly making the queue appear nonempty
-     * when a push, pop, or poll have not fully committed, or making
-     * it appear empty when an update of top has not yet been visibly
-     * written.  (Method isEmpty() checks the case of a partially
-     * completed removal of the last element.)  Because of this, the
-     * poll operation, considered individually, is not wait-free. One
-     * thief cannot successfully continue until another in-progress
-     * one (or, if previously empty, a push) visibly completes.
-     * However, in the aggregate, we ensure at least probabilistic
+     * guide where to extract from. We do not usually require strict
+     * orderings of array and index updates. Many index accesses use
+     * plain mode, with ordering constrained by surrounding context
+     * (usually with respect to element CASes or the two WorkQueue
+     * volatile fields source and phase). When not otherwise already
+     * constrained, reads of "base" by queue owners use acquire-mode,
+     * and some externally callable methods preface accesses with
+     * acquire fences.  Additionally, to ensure that index update
+     * writes are not coalesced or postponed in loops etc, "opaque"
+     * mode is used in a few cases where timely writes are not
+     * otherwise ensured. The "locked" versions of push- and pop-
+     * based methods for shared queues differ from owned versions
+     * because locking already forces some of the ordering.
+     *
+     * Because indices and slot contents cannot always be consistent,
+     * a check that base == top indicates (momentary) emptiness, but
+     * otherwise may err on the side of possibly making the queue
+     * appear nonempty when a push, pop, or poll have not fully
+     * committed, or making it appear empty when an update of top has
+     * not yet been visibly written.  (Method isEmpty() checks the
+     * case of a partially completed removal of the last element.)
+     * Because of this, the poll operation, considered individually,
+     * is not wait-free. One thief cannot successfully continue until
+     * another in-progress one (or, if previously empty, a push)
+     * visibly completes.  This can stall threads when required to
+     * consume from a given queue (see method poll()).  However, in
+     * the aggregate, we ensure at least probabilistic
      * non-blockingness.  If an attempted steal fails, a scanning
      * thief chooses a different random victim target to try next. So,
      * in order for one thief to progress, it suffices for any
-     * in-progress poll or new push on any empty queue to
-     * complete. (This is why we normally use method pollAt and its
-     * variants that try once at the apparent base index, else
-     * consider alternative actions, rather than method poll, which
-     * retries.)
+     * in-progress poll or new push on any empty queue to complete.
      *
      * This approach also enables support of a user mode in which
      * local task processing is in FIFO, not LIFO order, simply by
@@ -283,16 +309,13 @@
      * choosing existing queues, and may be randomly repositioned upon
      * contention with other submitters.  In essence, submitters act
      * like workers except that they are restricted to executing local
-     * tasks that they submitted (or in the case of CountedCompleters,
-     * others with the same root task).  Insertion of tasks in shared
-     * mode requires a lock but we use only a simple spinlock (using
-     * field qlock), because submitters encountering a busy queue move
-     * on to try or create other queues -- they block only when
-     * creating and registering new queues. Because it is used only as
-     * a spinlock, unlocking requires only a "releasing" store (using
-     * putOrderedInt).  The qlock is also used during termination
-     * detection, in which case it is forced to a negative
-     * non-lockable value.
+     * tasks that they submitted.  Insertion of tasks in shared mode
+     * requires a lock but we use only a simple spinlock (using field
+     * phase), because submitters encountering a busy queue move to a
+     * different position to use or create other queues -- they block
+     * only when creating and registering new queues. Because it is
+     * used only as a spinlock, unlocking requires only a "releasing"
+     * store (using setRelease) unless otherwise signalling.
      *
      * Management
      * ==========
@@ -306,43 +329,36 @@
      * There are only a few properties that we can globally track or
      * maintain, so we pack them into a small number of variables,
      * often maintaining atomicity without blocking or locking.
-     * Nearly all essentially atomic control state is held in two
+     * Nearly all essentially atomic control state is held in a few
      * volatile variables that are by far most often read (not
-     * written) as status and consistency checks. (Also, field
-     * "config" holds unchanging configuration state.)
+     * written) as status and consistency checks. We pack as much
+     * information into them as we can.
      *
      * Field "ctl" contains 64 bits holding information needed to
-     * atomically decide to add, inactivate, enqueue (on an event
-     * queue), dequeue, and/or re-activate workers.  To enable this
-     * packing, we restrict maximum parallelism to (1<<15)-1 (which is
-     * far in excess of normal operating range) to allow ids, counts,
-     * and their negations (used for thresholding) to fit into 16bit
+     * atomically decide to add, enqueue (on an event queue), and
+     * dequeue and release workers.  To enable this packing, we
+     * restrict maximum parallelism to (1<<15)-1 (which is far in
+     * excess of normal operating range) to allow ids, counts, and
+     * their negations (used for thresholding) to fit into 16bit
      * subfields.
      *
-     * Field "runState" holds lifetime status, atomically and
-     * monotonically setting STARTED, SHUTDOWN, STOP, and finally
-     * TERMINATED bits.
-     *
-     * Field "auxState" is a ReentrantLock subclass that also
-     * opportunistically holds some other bookkeeping fields accessed
-     * only when locked.  It is mainly used to lock (infrequent)
-     * updates to workQueues.  The auxState instance is itself lazily
-     * constructed (see tryInitialize), requiring a double-check-style
-     * bootstrapping use of field runState, and locking a private
-     * static.
+     * Field "mode" holds configuration parameters as well as lifetime
+     * status, atomically and monotonically setting SHUTDOWN, STOP,
+     * and finally TERMINATED bits.
      *
      * Field "workQueues" holds references to WorkQueues.  It is
-     * updated (only during worker creation and termination) under the
-     * lock, but is otherwise concurrently readable, and accessed
-     * directly. We also ensure that reads of the array reference
-     * itself never become too stale (for example, re-reading before
-     * each scan). To simplify index-based operations, the array size
-     * is always a power of two, and all readers must tolerate null
-     * slots. Worker queues are at odd indices. Shared (submission)
-     * queues are at even indices, up to a maximum of 64 slots, to
-     * limit growth even if array needs to expand to add more
-     * workers. Grouping them together in this way simplifies and
-     * speeds up task scanning.
+     * updated (only during worker creation and termination) under
+     * lock (using field workerNamePrefix as lock), but is otherwise
+     * concurrently readable, and accessed directly. We also ensure
+     * that uses of the array reference itself never become too stale
+     * in case of resizing, by arranging that (re-)reads are separated
+     * by at least one acquiring read access.  To simplify index-based
+     * operations, the array size is always a power of two, and all
+     * readers must tolerate null slots. Worker queues are at odd
+     * indices. Shared (submission) queues are at even indices, up to
+     * a maximum of 64 slots, to limit growth even if the array needs
+     * to expand to add more workers. Grouping them together in this
+     * way simplifies and speeds up task scanning.
      *
      * All worker thread creation is on-demand, triggered by task
      * submissions, replacement of terminated workers, and/or
@@ -361,30 +377,37 @@
      * workers unless there appear to be tasks available.  On the
      * other hand, we must quickly prod them into action when new
      * tasks are submitted or generated. In many usages, ramp-up time
-     * to activate workers is the main limiting factor in overall
-     * performance, which is compounded at program start-up by JIT
-     * compilation and allocation. So we streamline this as much as
-     * possible.
+     * is the main limiting factor in overall performance, which is
+     * compounded at program start-up by JIT compilation and
+     * allocation. So we streamline this as much as possible.
      *
-     * The "ctl" field atomically maintains active and total worker
-     * counts as well as a queue to place waiting threads so they can
-     * be located for signalling. Active counts also play the role of
-     * quiescence indicators, so are decremented when workers believe
-     * that there are no more tasks to execute. The "queue" is
-     * actually a form of Treiber stack.  A stack is ideal for
-     * activating threads in most-recently used order. This improves
+     * The "ctl" field atomically maintains total worker and
+     * "released" worker counts, plus the head of the available worker
+     * queue (actually stack, represented by the lower 32bit subfield
+     * of ctl).  Released workers are those known to be scanning for
+     * and/or running tasks. Unreleased ("available") workers are
+     * recorded in the ctl stack. These workers are made available for
+     * signalling by enqueuing in ctl (see method runWorker).  The
+     * "queue" is a form of Treiber stack. This is ideal for
+     * activating threads in most-recently used order, and improves
      * performance and locality, outweighing the disadvantages of
      * being prone to contention and inability to release a worker
-     * unless it is topmost on stack.  We block/unblock workers after
-     * pushing on the idle worker stack (represented by the lower
-     * 32bit subfield of ctl) when they cannot find work.  The top
-     * stack state holds the value of the "scanState" field of the
-     * worker: its index and status, plus a version counter that, in
-     * addition to the count subfields (also serving as version
-     * stamps) provide protection against Treiber stack ABA effects.
+     * unless it is topmost on stack.  To avoid missed signal problems
+     * inherent in any wait/signal design, available workers rescan
+     * for (and if found run) tasks after enqueuing.  Normally their
+     * release status will be updated while doing so, but the released
+     * worker ctl count may underestimate the number of active
+     * threads. (However, it is still possible to determine quiescence
+     * via a validation traversal -- see isQuiescent).  After an
+     * unsuccessful rescan, available workers are blocked until
+     * signalled (see signalWork).  The top stack state holds the
+     * value of the "phase" field of the worker: its index and status,
+     * plus a version counter that, in addition to the count subfields
+     * (also serving as version stamps) provide protection against
+     * Treiber stack ABA effects.
      *
-     * Creating workers. To create a worker, we pre-increment total
-     * count (serving as a reservation), and attempt to construct a
+     * Creating workers. To create a worker, we pre-increment counts
+     * (serving as a reservation), and attempt to construct a
      * ForkJoinWorkerThread via its factory. Upon construction, the
      * new thread invokes registerWorker, where it constructs a
      * WorkQueue and is assigned an index in the workQueues array
@@ -406,15 +429,14 @@
      * submission queues for existing external threads (see
      * externalPush).
      *
-     * WorkQueue field scanState is used by both workers and the pool
-     * to manage and track whether a worker is UNSIGNALLED (possibly
-     * blocked waiting for a signal).  When a worker is inactivated,
-     * its scanState field is set, and is prevented from executing
-     * tasks, even though it must scan once for them to avoid queuing
-     * races. Note that scanState updates lag queue CAS releases so
-     * usage requires care. When queued, the lower 16 bits of
-     * scanState must hold its pool index. So we place the index there
-     * upon initialization (see registerWorker) and otherwise keep it
+     * WorkQueue field "phase" is used by both workers and the pool to
+     * manage and track whether a worker is UNSIGNALLED (possibly
+     * blocked waiting for a signal).  When a worker is enqueued its
+     * phase field is set. Note that phase field updates lag queue CAS
+     * releases so usage requires care -- seeing a negative phase does
+     * not guarantee that the worker is available. When queued, the
+     * lower 16 bits of scanState must hold its pool index. So we
+     * place the index there upon initialization and otherwise keep it
      * there or restore it when necessary.
      *
      * The ctl field also serves as the basis for memory
@@ -423,85 +445,68 @@
      * consumers sync with each other by both writing/CASing ctl (even
      * if to its current value).  This would be extremely costly. So
      * we relax it in several ways: (1) Producers only signal when
-     * their queue is empty. Other workers propagate this signal (in
-     * method scan) when they find tasks. (2) Workers only enqueue
-     * after scanning (see below) and not finding any tasks.  (3)
-     * Rather than CASing ctl to its current value in the common case
-     * where no action is required, we reduce write contention by
-     * equivalently prefacing signalWork when called by an external
-     * task producer using a memory access with full-volatile
-     * semantics or a "fullFence". (4) For internal task producers we
-     * rely on the fact that even if no other workers awaken, the
-     * producer itself will eventually see the task and execute it.
+     * their queue is possibly empty at some point during a push
+     * operation (which requires conservatively checking size zero or
+     * one to cover races). (2) Other workers propagate this signal
+     * when they find tasks in a queue with size greater than one. (3)
+     * Workers only enqueue after scanning (see below) and not finding
+     * any tasks.  (4) Rather than CASing ctl to its current value in
+     * the common case where no action is required, we reduce write
+     * contention by equivalently prefacing signalWork when called by
+     * an external task producer using a memory access with
+     * full-volatile semantics or a "fullFence".
      *
-     * Almost always, too many signals are issued. A task producer
-     * cannot in general tell if some existing worker is in the midst
-     * of finishing one task (or already scanning) and ready to take
-     * another without being signalled. So the producer might instead
-     * activate a different worker that does not find any work, and
-     * then inactivates. This scarcely matters in steady-state
-     * computations involving all workers, but can create contention
-     * and bookkeeping bottlenecks during ramp-up, ramp-down, and small
-     * computations involving only a few workers.
+     * Almost always, too many signals are issued, in part because a
+     * task producer cannot tell if some existing worker is in the
+     * midst of finishing one task (or already scanning) and ready to
+     * take another without being signalled. So the producer might
+     * instead activate a different worker that does not find any
+     * work, and then inactivates. This scarcely matters in
+     * steady-state computations involving all workers, but can create
+     * contention and bookkeeping bottlenecks during ramp-up,
+     * ramp-down, and small computations involving only a few workers.
      *
-     * Scanning. Method scan() performs top-level scanning for tasks.
-     * Each scan traverses (and tries to poll from) each queue in
-     * pseudorandom permutation order by randomly selecting an origin
-     * index and a step value.  (The pseudorandom generator need not
-     * have high-quality statistical properties in the long term, but
-     * just within computations; We use 64bit and 32bit Marsaglia
-     * XorShifts, which are cheap and suffice here.)  Scanning also
-     * employs contention reduction: When scanning workers fail a CAS
-     * polling for work, they soon restart with a different
-     * pseudorandom scan order (thus likely retrying at different
-     * intervals). This improves throughput when many threads are
-     * trying to take tasks from few queues.  Scans do not otherwise
-     * explicitly take into account core affinities, loads, cache
-     * localities, etc, However, they do exploit temporal locality
-     * (which usually approximates these) by preferring to re-poll (up
-     * to POLL_LIMIT times) from the same queue after a successful
-     * poll before trying others.  Restricted forms of scanning occur
-     * in methods helpComplete and findNonEmptyStealQueue, and take
-     * similar but simpler forms.
-     *
-     * Deactivation and waiting. Queuing encounters several intrinsic
-     * races; most notably that an inactivating scanning worker can
-     * miss seeing a task produced during a scan.  So when a worker
-     * cannot find a task to steal, it inactivates and enqueues, and
-     * then rescans to ensure that it didn't miss one, reactivating
-     * upon seeing one with probability approximately proportional to
-     * probability of a miss.  (In most cases, the worker will be
-     * signalled before self-signalling, avoiding cascades of multiple
-     * signals for the same task).
-     *
-     * Workers block (in method awaitWork) using park/unpark;
-     * advertising the need for signallers to unpark by setting their
-     * "parker" fields.
+     * Scanning. Method scan (from runWorker) performs top-level
+     * scanning for tasks. (Similar scans appear in helpQuiesce and
+     * pollScan.)  Each scan traverses and tries to poll from each
+     * queue starting at a random index. Scans are not performed in
+     * ideal random permutation order, to reduce cacheline
+     * contention. The pseudorandom generator need not have
+     * high-quality statistical properties in the long term, but just
+     * within computations; We use Marsaglia XorShifts (often via
+     * ThreadLocalRandom.nextSecondarySeed), which are cheap and
+     * suffice. Scanning also includes contention reduction: When
+     * scanning workers fail to extract an apparently existing task,
+     * they soon restart at a different pseudorandom index.  This form
+     * of backoff improves throughput when many threads are trying to
+     * take tasks from few queues, which can be common in some usages.
+     * Scans do not otherwise explicitly take into account core
+     * affinities, loads, cache localities, etc, However, they do
+     * exploit temporal locality (which usually approximates these) by
+     * preferring to re-poll from the same queue after a successful
+     * poll before trying others (see method topLevelExec). However
+     * this preference is bounded (see TOP_BOUND_SHIFT) as a safeguard
+     * against infinitely unfair looping under unbounded user task
+     * recursion, and also to reduce long-term contention when many
+     * threads poll few queues holding many small tasks. The bound is
+     * high enough to avoid much impact on locality and scheduling
+     * overhead.
      *
      * Trimming workers. To release resources after periods of lack of
      * use, a worker starting to wait when the pool is quiescent will
-     * time out and terminate (see awaitWork) if the pool has remained
-     * quiescent for period given by IDLE_TIMEOUT_MS, increasing the
-     * period as the number of threads decreases, eventually removing
-     * all workers.
+     * time out and terminate (see method runWorker) if the pool has
+     * remained quiescent for period given by field keepAlive.
      *
      * Shutdown and Termination. A call to shutdownNow invokes
      * tryTerminate to atomically set a runState bit. The calling
      * thread, as well as every other worker thereafter terminating,
-     * helps terminate others by setting their (qlock) status,
-     * cancelling their unprocessed tasks, and waking them up, doing
-     * so repeatedly until stable. Calls to non-abrupt shutdown()
-     * preface this by checking whether termination should commence.
-     * This relies primarily on the active count bits of "ctl"
-     * maintaining consensus -- tryTerminate is called from awaitWork
-     * whenever quiescent. However, external submitters do not take
-     * part in this consensus.  So, tryTerminate sweeps through queues
-     * (until stable) to ensure lack of in-flight submissions and
-     * workers about to process them before triggering the "STOP"
-     * phase of termination. (Note: there is an intrinsic conflict if
-     * helpQuiescePool is called when shutdown is enabled. Both wait
-     * for quiescence, but tryTerminate is biased to not trigger until
-     * helpQuiescePool completes.)
+     * helps terminate others by cancelling their unprocessed tasks,
+     * and waking them up, doing so repeatedly until stable. Calls to
+     * non-abrupt shutdown() preface this by checking whether
+     * termination should commence by sweeping through queues (until
+     * stable) to ensure lack of in-flight submissions and workers
+     * about to process them before triggering the "STOP" phase of
+     * termination.
      *
      * Joining Tasks
      * =============
@@ -509,12 +514,12 @@
      * Any of several actions may be taken when one worker is waiting
      * to join a task stolen (or always held) by another.  Because we
      * are multiplexing many tasks on to a pool of workers, we can't
-     * just let them block (as in Thread.join).  We also cannot just
-     * reassign the joiner's run-time stack with another and replace
-     * it later, which would be a form of "continuation", that even if
-     * possible is not necessarily a good idea since we may need both
-     * an unblocked task and its continuation to progress.  Instead we
-     * combine two tactics:
+     * always just let them block (as in Thread.join).  We also cannot
+     * just reassign the joiner's run-time stack with another and
+     * replace it later, which would be a form of "continuation", that
+     * even if possible is not necessarily a good idea since we may
+     * need both an unblocked task and its continuation to progress.
+     * Instead we combine two tactics:
      *
      *   Helping: Arranging for the joiner to execute some task that it
      *      would be running if the steal had not occurred.
@@ -527,79 +532,44 @@
      * helping a hypothetical compensator: If we can readily tell that
      * a possible action of a compensator is to steal and execute the
      * task being joined, the joining thread can do so directly,
-     * without the need for a compensation thread (although at the
-     * expense of larger run-time stacks, but the tradeoff is
-     * typically worthwhile).
+     * without the need for a compensation thread.
      *
      * The ManagedBlocker extension API can't use helping so relies
      * only on compensation in method awaitBlocker.
      *
-     * The algorithm in helpStealer entails a form of "linear
-     * helping".  Each worker records (in field currentSteal) the most
-     * recent task it stole from some other worker (or a submission).
-     * It also records (in field currentJoin) the task it is currently
-     * actively joining. Method helpStealer uses these markers to try
-     * to find a worker to help (i.e., steal back a task from and
-     * execute it) that could hasten completion of the actively joined
-     * task.  Thus, the joiner executes a task that would be on its
-     * own local deque had the to-be-joined task not been stolen. This
-     * is a conservative variant of the approach described in Wagner &
-     * Calder "Leapfrogging: a portable technique for implementing
-     * efficient futures" SIGPLAN Notices, 1993
-     * (http://portal.acm.org/citation.cfm?id=155354). It differs in
-     * that: (1) We only maintain dependency links across workers upon
-     * steals, rather than use per-task bookkeeping.  This sometimes
-     * requires a linear scan of workQueues array to locate stealers,
-     * but often doesn't because stealers leave hints (that may become
-     * stale/wrong) of where to locate them.  It is only a hint
-     * because a worker might have had multiple steals and the hint
-     * records only one of them (usually the most current).  Hinting
-     * isolates cost to when it is needed, rather than adding to
-     * per-task overhead.  (2) It is "shallow", ignoring nesting and
-     * potentially cyclic mutual steals.  (3) It is intentionally
-     * racy: field currentJoin is updated only while actively joining,
-     * which means that we miss links in the chain during long-lived
-     * tasks, GC stalls etc (which is OK since blocking in such cases
-     * is usually a good idea).  (4) We bound the number of attempts
-     * to find work using checksums and fall back to suspending the
-     * worker and if necessary replacing it with another.
+     * The algorithm in awaitJoin entails a form of "linear helping".
+     * Each worker records (in field source) the id of the queue from
+     * which it last stole a task.  The scan in method awaitJoin uses
+     * these markers to try to find a worker to help (i.e., steal back
+     * a task from and execute it) that could hasten completion of the
+     * actively joined task.  Thus, the joiner executes a task that
+     * would be on its own local deque if the to-be-joined task had
+     * not been stolen. This is a conservative variant of the approach
+     * described in Wagner & Calder "Leapfrogging: a portable
+     * technique for implementing efficient futures" SIGPLAN Notices,
+     * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
+     * mainly in that we only record queue ids, not full dependency
+     * links.  This requires a linear scan of the workQueues array to
+     * locate stealers, but isolates cost to when it is needed, rather
+     * than adding to per-task overhead. Searches can fail to locate
+     * stealers GC stalls and the like delay recording sources.
+     * Further, even when accurately identified, stealers might not
+     * ever produce a task that the joiner can in turn help with. So,
+     * compensation is tried upon failure to find tasks to run.
      *
-     * Helping actions for CountedCompleters do not require tracking
-     * currentJoins: Method helpComplete takes and executes any task
-     * with the same root as the task being waited on (preferring
-     * local pops to non-local polls). However, this still entails
-     * some traversal of completer chains, so is less efficient than
-     * using CountedCompleters without explicit joins.
-     *
-     * Compensation does not aim to keep exactly the target
+     * Compensation does not by default aim to keep exactly the target
      * parallelism number of unblocked threads running at any given
      * time. Some previous versions of this class employed immediate
      * compensations for any blocked join. However, in practice, the
      * vast majority of blockages are transient byproducts of GC and
-     * other JVM or OS activities that are made worse by replacement.
-     * Currently, compensation is attempted only after validating that
-     * all purportedly active threads are processing tasks by checking
-     * field WorkQueue.scanState, which eliminates most false
-     * positives.  Also, compensation is bypassed (tolerating fewer
-     * threads) in the most common case in which it is rarely
-     * beneficial: when a worker with an empty queue (thus no
-     * continuation tasks) blocks on a join and there still remain
-     * enough threads to ensure liveness.
-     *
-     * Spare threads are removed as soon as they notice that the
-     * target parallelism level has been exceeded, in method
-     * tryDropSpare. (Method scan arranges returns for rechecks upon
-     * each probe via the "bound" parameter.)
-     *
-     * The compensation mechanism may be bounded.  Bounds for the
+     * other JVM or OS activities that are made worse by replacement
+     * when they cause longer-term oversubscription.  Rather than
+     * impose arbitrary policies, we allow users to override the
+     * default of only adding threads upon apparent starvation.  The
+     * compensation mechanism may also be bounded.  Bounds for the
      * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
      * with programming errors and abuse before running out of
-     * resources to do so. In other cases, users may supply factories
-     * that limit thread construction. The effects of bounding in this
-     * pool (like all others) is imprecise.  Total worker counts are
-     * decremented when threads deregister, not when they exit and
-     * resources are reclaimed by the JVM and OS. So the number of
-     * simultaneously live threads may transiently exceed bounds.
+     * resources to do so.
      *
      * Common Pool
      * ===========
@@ -607,9 +577,7 @@
      * The static common pool always exists after static
      * initialization.  Since it (or any other created pool) need
      * never be used, we minimize initial construction overhead and
-     * footprint to the setup of about a dozen fields, with no nested
-     * allocation. Most bootstrapping occurs within method
-     * externalSubmit during the first submission to the pool.
+     * footprint to the setup of about a dozen fields.
      *
      * When external threads submit to the common pool, they can
      * perform subtask processing (see externalHelpComplete and
@@ -629,31 +597,39 @@
      * InnocuousForkJoinWorkerThread when there is a SecurityManager
      * present. These workers have no permissions set, do not belong
      * to any user-defined ThreadGroup, and erase all ThreadLocals
-     * after executing any top-level task (see WorkQueue.runTask).
-     * The associated mechanics (mainly in ForkJoinWorkerThread) may
-     * be JVM-dependent and must access particular Thread class fields
-     * to achieve this effect.
+     * after executing any top-level task (see
+     * WorkQueue.afterTopLevelExec).  The associated mechanics (mainly
+     * in ForkJoinWorkerThread) may be JVM-dependent and must access
+     * particular Thread class fields to achieve this effect.
+     *
+     * Memory placement
+     * ================
+     *
+     * Performance can be very sensitive to placement of instances of
+     * ForkJoinPool and WorkQueues and their queue arrays. To reduce
+     * false-sharing impact, the @Contended annotation isolates
+     * adjacent WorkQueue instances, as well as the ForkJoinPool.ctl
+     * field. WorkQueue arrays are allocated (by their threads) with
+     * larger initial sizes than most ever need, mostly to reduce
+     * false sharing with current garbage collectors that use cardmark
+     * tables.
      *
      * Style notes
      * ===========
      *
-     * Memory ordering relies mainly on Unsafe intrinsics that carry
-     * the further responsibility of explicitly performing null- and
-     * bounds- checks otherwise carried out implicitly by JVMs.  This
-     * can be awkward and ugly, but also reflects the need to control
+     * Memory ordering relies mainly on VarHandles.  This can be
+     * awkward and ugly, but also reflects the need to control
      * outcomes across the unusual cases that arise in very racy code
-     * with very few invariants. So these explicit checks would exist
-     * in some form anyway.  All fields are read into locals before
-     * use, and null-checked if they are references.  This is usually
-     * done in a "C"-like style of listing declarations at the heads
-     * of methods or blocks, and using inline assignments on first
-     * encounter.  Array bounds-checks are usually performed by
-     * masking with array.length-1, which relies on the invariant that
-     * these arrays are created with positive lengths, which is itself
-     * paranoically checked. Nearly all explicit checks lead to
-     * bypass/return, not exception throws, because they may
-     * legitimately arise due to cancellation/revocation during
-     * shutdown.
+     * with very few invariants. All fields are read into locals
+     * before use, and null-checked if they are references.  Array
+     * accesses using masked indices include checks (that are always
+     * true) that the array length is non-zero to avoid compilers
+     * inserting more expensive traps.  This is usually done in a
+     * "C"-like style of listing declarations at the heads of methods
+     * or blocks, and using inline assignments on first encounter.
+     * Nearly all explicit checks lead to bypass/return, not exception
+     * throws, because they may legitimately arise due to
+     * cancellation/revocation during shutdown.
      *
      * There is a lot of representation-level coupling among classes
      * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask.  The
@@ -663,10 +639,11 @@
      * representations will need to be accompanied by algorithmic
      * changes anyway. Several methods intrinsically sprawl because
      * they must accumulate sets of consistent reads of fields held in
-     * local variables.  There are also other coding oddities
-     * (including several unnecessary-looking hoisted null checks)
-     * that help some methods perform reasonably even when interpreted
-     * (not compiled).
+     * local variables. Some others are artificially broken up to
+     * reduce producer/consumer imbalances due to dynamic compilation.
+     * There are also other coding oddities (including several
+     * unnecessary-looking hoisted null checks) that help some methods
+     * perform reasonably even when interpreted (not compiled).
      *
      * The order of declarations in this file is (with a few exceptions):
      * (1) Static utility functions
@@ -702,6 +679,13 @@
     public static interface ForkJoinWorkerThreadFactory {
         /**
          * Returns a new worker thread operating in the given pool.
+         * Returning null or throwing an exception may result in tasks
+         * never being executed.  If this method throws an exception,
+         * it is relayed to the caller of the method (for example
+         * {@code execute}) causing attempted thread creation. If this
+         * method returns null or throws an exception, it is not
+         * retried until the next attempted creation (for example
+         * another call to {@code execute}).
          *
          * @param pool the pool this thread works in
          * @return the new worker thread, or {@code null} if the request
@@ -711,120 +695,97 @@
         public ForkJoinWorkerThread newThread(ForkJoinPool pool);
     }
 
+    static AccessControlContext contextWithPermissions(Permission ... perms) {
+        Permissions permissions = new Permissions();
+        for (Permission perm : perms)
+            permissions.add(perm);
+        return new AccessControlContext(
+            new ProtectionDomain[] { new ProtectionDomain(null, permissions) });
+    }
+
     /**
      * Default ForkJoinWorkerThreadFactory implementation; creates a
-     * new ForkJoinWorkerThread.
+     * new ForkJoinWorkerThread using the system class loader as the
+     * thread context class loader.
      */
     private static final class DefaultForkJoinWorkerThreadFactory
         implements ForkJoinWorkerThreadFactory {
+        private static final AccessControlContext ACC = contextWithPermissions(
+            new RuntimePermission("getClassLoader"),
+            new RuntimePermission("setContextClassLoader"));
+
         public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
-            return new ForkJoinWorkerThread(pool);
+            return AccessController.doPrivileged(
+                new PrivilegedAction<>() {
+                    public ForkJoinWorkerThread run() {
+                        return new ForkJoinWorkerThread(
+                            pool, ClassLoader.getSystemClassLoader()); }},
+                ACC);
         }
     }
 
-    /**
-     * Class for artificial tasks that are used to replace the target
-     * of local joins if they are removed from an interior queue slot
-     * in WorkQueue.tryRemoveAndExec. We don't need the proxy to
-     * actually do anything beyond having a unique identity.
-     */
-    private static final class EmptyTask extends ForkJoinTask<Void> {
-        private static final long serialVersionUID = -7721805057305804111L;
-        EmptyTask() { status = ForkJoinTask.NORMAL; } // force done
-        public final Void getRawResult() { return null; }
-        public final void setRawResult(Void x) {}
-        public final boolean exec() { return true; }
-    }
-
-    /**
-     * Additional fields and lock created upon initialization.
-     */
-    private static final class AuxState extends ReentrantLock {
-        private static final long serialVersionUID = -6001602636862214147L;
-        volatile long stealCount;     // cumulative steal count
-        long indexSeed;               // index bits for registerWorker
-        AuxState() {}
-    }
-
     // Constants shared across ForkJoinPool and WorkQueue
 
     // Bounds
+    static final int SWIDTH       = 16;            // width of short
     static final int SMASK        = 0xffff;        // short bits == max index
     static final int MAX_CAP      = 0x7fff;        // max #workers - 1
-    static final int EVENMASK     = 0xfffe;        // even short bits
     static final int SQMASK       = 0x007e;        // max 64 (even) slots
 
-    // Masks and units for WorkQueue.scanState and ctl sp subfield
+    // Masks and units for WorkQueue.phase and ctl sp subfield
     static final int UNSIGNALLED  = 1 << 31;       // must be negative
     static final int SS_SEQ       = 1 << 16;       // version count
+    static final int QLOCK        = 1;             // must be 1
 
-    // Mode bits for ForkJoinPool.config and WorkQueue.config
-    static final int MODE_MASK    = 0xffff << 16;  // top half of int
-    static final int SPARE_WORKER = 1 << 17;       // set if tc > 0 on creation
-    static final int UNREGISTERED = 1 << 18;       // to skip some of deregister
-    static final int FIFO_QUEUE   = 1 << 31;       // must be negative
-    static final int LIFO_QUEUE   = 0;             // for clarity
-    static final int IS_OWNED     = 1;             // low bit 0 if shared
+    // Mode bits and sentinels, some also used in WorkQueue id and.source fields
+    static final int OWNED        = 1;             // queue has owner thread
+    static final int FIFO         = 1 << 16;       // fifo queue or access mode
+    static final int SHUTDOWN     = 1 << 18;
+    static final int TERMINATED   = 1 << 19;
+    static final int STOP         = 1 << 31;       // must be negative
+    static final int QUIET        = 1 << 30;       // not scanning or working
+    static final int DORMANT      = QUIET | UNSIGNALLED;
 
     /**
-     * The maximum number of task executions from the same queue
-     * before checking other queues, bounding unfairness and impact of
-     * infinite user task recursion.  Must be a power of two minus 1.
+     * Initial capacity of work-stealing queue array.
+     * Must be a power of two, at least 2.
      */
-    static final int POLL_LIMIT = (1 << 10) - 1;
+    static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+    /**
+     * Maximum capacity for queue arrays. Must be a power of two less
+     * than or equal to 1 << (31 - width of array entry) to ensure
+     * lack of wraparound of index calculations, but defined to a
+     * value a bit less than this to help users trap runaway programs
+     * before saturating systems.
+     */
+    static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
+
+    /**
+     * The maximum number of top-level polls per worker before
+     * checking other queues, expressed as a bit shift to, in effect,
+     * multiply by pool size, and then use as random value mask, so
+     * average bound is about poolSize*(1<<TOP_BOUND_SHIFT).  See
+     * above for rationale.
+     */
+    static final int TOP_BOUND_SHIFT = 10;
 
     /**
      * Queues supporting work-stealing as well as external task
      * submission. See above for descriptions and algorithms.
-     * Performance on most platforms is very sensitive to placement of
-     * instances of both WorkQueues and their arrays -- we absolutely
-     * do not want multiple WorkQueue instances or multiple queue
-     * arrays sharing cache lines. The @Contended annotation alerts
-     * JVMs to try to keep instances apart.
      */
-    // Android-removed: @Contended, this hint is not used by the Android runtime.
-    //@jdk.internal.vm.annotation.Contended
+    @jdk.internal.vm.annotation.Contended
     static final class WorkQueue {
-
-        /**
-         * Capacity of work-stealing queue array upon initialization.
-         * Must be a power of two; at least 4, but should be larger to
-         * reduce or eliminate cacheline sharing among queues.
-         * Currently, it is much larger, as a partial workaround for
-         * the fact that JVMs often place arrays in locations that
-         * share GC bookkeeping (especially cardmarks) such that
-         * per-write accesses encounter serious memory contention.
-         */
-        static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
-
-        /**
-         * Maximum size for queue arrays. Must be a power of two less
-         * than or equal to 1 << (31 - width of array entry) to ensure
-         * lack of wraparound of index calculations, but defined to a
-         * value a bit less than this to help users trap runaway
-         * programs before saturating systems.
-         */
-        static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
-
-        // Instance fields
-
-        volatile int scanState;    // versioned, negative if inactive
-        int stackPred;             // pool stack (ctl) predecessor
-        int nsteals;               // number of steals
-        int hint;                  // randomization and stealer index hint
-        int config;                // pool index and mode
-        volatile int qlock;        // 1: locked, < 0: terminate; else 0
-        volatile int base;         // index of next slot for poll
+        volatile int source;       // source queue id, or sentinel
+        int id;                    // pool index, mode, tag
+        int base;                  // index of next slot for poll
         int top;                   // index of next slot for push
-        ForkJoinTask<?>[] array;   // the elements (initially unallocated)
+        volatile int phase;        // versioned, negative: queued, 1: locked
+        int stackPred;             // pool stack (ctl) predecessor link
+        int nsteals;               // number of steals
+        ForkJoinTask<?>[] array;   // the queued tasks; power of 2 size
         final ForkJoinPool pool;   // the containing pool (may be null)
         final ForkJoinWorkerThread owner; // owning thread or null if shared
-        volatile Thread parker;    // == owner during call to park; else null
-        volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin
-
-      // Android-removed: @Contended, this hint is not used by the Android runtime.
-      // @jdk.internal.vm.annotation.Contended("group2") // segregate
-        volatile ForkJoinTask<?> currentSteal; // nonnull when running some task
 
         WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) {
             this.pool = pool;
@@ -834,17 +795,28 @@
         }
 
         /**
+         * Tries to lock shared queue by CASing phase field.
+         */
+        final boolean tryLockPhase() {
+            return PHASE.compareAndSet(this, 0, 1);
+        }
+
+        final void releasePhaseLock() {
+            PHASE.setRelease(this, 0);
+        }
+
+        /**
          * Returns an exportable index (used by ForkJoinWorkerThread).
          */
         final int getPoolIndex() {
-            return (config & 0xffff) >>> 1; // ignore odd/even tag bit
+            return (id & 0xffff) >>> 1; // ignore odd/even tag bit
         }
 
         /**
          * Returns the approximate number of tasks in the queue.
          */
         final int queueSize() {
-            int n = base - top;       // read base first
+            int n = (int)BASE.getAcquire(this) - top;
             return (n >= 0) ? 0 : -n; // ignore transient negative
         }
 
@@ -854,11 +826,12 @@
          * near-empty queue has at least one unclaimed task.
          */
         final boolean isEmpty() {
-            ForkJoinTask<?>[] a; int n, al, s;
-            return ((n = base - (s = top)) >= 0 || // possibly one task
+            ForkJoinTask<?>[] a; int n, cap, b;
+            VarHandle.acquireFence(); // needed by external callers
+            return ((n = (b = base) - top) >= 0 || // possibly one task
                     (n == -1 && ((a = array) == null ||
-                                 (al = a.length) == 0 ||
-                                 a[(al - 1) & (s - 1)] == null)));
+                                 (cap = a.length) == 0 ||
+                                 a[(cap - 1) & b] == null)));
         }
 
         /**
@@ -868,116 +841,99 @@
          * @throws RejectedExecutionException if array cannot be resized
          */
         final void push(ForkJoinTask<?> task) {
-            U.storeFence();              // ensure safe publication
-            int s = top, al, d; ForkJoinTask<?>[] a;
-            if ((a = array) != null && (al = a.length) > 0) {
-                a[(al - 1) & s] = task;  // relaxed writes OK
+            ForkJoinTask<?>[] a;
+            int s = top, d, cap, m;
+            ForkJoinPool p = pool;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                QA.setRelease(a, (m = cap - 1) & s, task);
                 top = s + 1;
-                ForkJoinPool p = pool;
-                if ((d = base - s) == 0 && p != null) {
-                    U.fullFence();
+                if (((d = s - (int)BASE.getAcquire(this)) & ~1) == 0 &&
+                    p != null) {                 // size 0 or 1
+                    VarHandle.fullFence();
                     p.signalWork();
                 }
-                else if (al + d == 1)
-                    growArray();
+                else if (d == m)
+                    growArray(false);
             }
         }
 
         /**
-         * Initializes or doubles the capacity of array. Call either
-         * by owner or with lock held -- it is OK for base, but not
-         * top, to move while resizings are in progress.
+         * Version of push for shared queues. Call only with phase lock held.
+         * @return true if should signal work
          */
-        final ForkJoinTask<?>[] growArray() {
-            ForkJoinTask<?>[] oldA = array;
-            int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
-            if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY)
+        final boolean lockedPush(ForkJoinTask<?> task) {
+            ForkJoinTask<?>[] a;
+            boolean signal = false;
+            int s = top, b = base, cap, d;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                a[(cap - 1) & s] = task;
+                top = s + 1;
+                if (b - s + cap - 1 == 0)
+                    growArray(true);
+                else {
+                    phase = 0; // full volatile unlock
+                    if (((s - base) & ~1) == 0) // size 0 or 1
+                        signal = true;
+                }
+            }
+            return signal;
+        }
+
+        /**
+         * Doubles the capacity of array. Call either by owner or with
+         * lock held -- it is OK for base, but not top, to move while
+         * resizings are in progress.
+         */
+        final void growArray(boolean locked) {
+            ForkJoinTask<?>[] newA = null;
+            try {
+                ForkJoinTask<?>[] oldA; int oldSize, newSize;
+                if ((oldA = array) != null && (oldSize = oldA.length) > 0 &&
+                    (newSize = oldSize << 1) <= MAXIMUM_QUEUE_CAPACITY &&
+                    newSize > 0) {
+                    try {
+                        newA = new ForkJoinTask<?>[newSize];
+                    } catch (OutOfMemoryError ex) {
+                    }
+                    if (newA != null) { // poll from old array, push to new
+                        int oldMask = oldSize - 1, newMask = newSize - 1;
+                        for (int s = top - 1, k = oldMask; k >= 0; --k) {
+                            ForkJoinTask<?> x = (ForkJoinTask<?>)
+                                QA.getAndSet(oldA, s & oldMask, null);
+                            if (x != null)
+                                newA[s-- & newMask] = x;
+                            else
+                                break;
+                        }
+                        array = newA;
+                        VarHandle.releaseFence();
+                    }
+                }
+            } finally {
+                if (locked)
+                    phase = 0;
+            }
+            if (newA == null)
                 throw new RejectedExecutionException("Queue capacity exceeded");
-            int oldMask, t, b;
-            ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
-            if (oldA != null && (oldMask = oldA.length - 1) > 0 &&
-                (t = top) - (b = base) > 0) {
-                int mask = size - 1;
-                do { // emulate poll from old array, push to new array
-                    int index = b & oldMask;
-                    long offset = ((long)index << ASHIFT) + ABASE;
-                    ForkJoinTask<?> x = (ForkJoinTask<?>)
-                        U.getObjectVolatile(oldA, offset);
-                    if (x != null &&
-                        U.compareAndSwapObject(oldA, offset, x, null))
-                        a[b & mask] = x;
-                } while (++b != t);
-                U.storeFence();
-            }
-            return a;
-        }
-
-        /**
-         * Takes next task, if one exists, in LIFO order.  Call only
-         * by owner in unshared queues.
-         */
-        final ForkJoinTask<?> pop() {
-            int b = base, s = top, al, i; ForkJoinTask<?>[] a;
-            if ((a = array) != null && b != s && (al = a.length) > 0) {
-                int index = (al - 1) & --s;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> t = (ForkJoinTask<?>)
-                    U.getObject(a, offset);
-                if (t != null &&
-                    U.compareAndSwapObject(a, offset, t, null)) {
-                    top = s;
-                    return t;
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Takes a task in FIFO order if b is base of queue and a task
-         * can be claimed without contention. Specialized versions
-         * appear in ForkJoinPool methods scan and helpStealer.
-         */
-        final ForkJoinTask<?> pollAt(int b) {
-            ForkJoinTask<?>[] a; int al;
-            if ((a = array) != null && (al = a.length) > 0) {
-                int index = (al - 1) & b;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> t = (ForkJoinTask<?>)
-                    U.getObjectVolatile(a, offset);
-                if (t != null && b++ == base &&
-                    U.compareAndSwapObject(a, offset, t, null)) {
-                    base = b;
-                    return t;
-                }
-            }
-            return null;
         }
 
         /**
          * Takes next task, if one exists, in FIFO order.
          */
         final ForkJoinTask<?> poll() {
-            for (;;) {
-                int b = base, s = top, d, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && (d = b - s) < 0 &&
-                    (al = a.length) > 0) {
-                    int index = (al - 1) & b;
-                    long offset = ((long)index << ASHIFT) + ABASE;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        U.getObjectVolatile(a, offset);
-                    if (b++ == base) {
-                        if (t != null) {
-                            if (U.compareAndSwapObject(a, offset, t, null)) {
-                                base = b;
-                                return t;
-                            }
-                        }
-                        else if (d == -1)
-                            break; // now empty
+            int b, k, cap; ForkJoinTask<?>[] a;
+            while ((a = array) != null && (cap = a.length) > 0 &&
+                   top - (b = base) > 0) {
+                ForkJoinTask<?> t = (ForkJoinTask<?>)
+                    QA.getAcquire(a, k = (cap - 1) & b);
+                if (base == b++) {
+                    if (t == null)
+                        Thread.yield(); // await index advance
+                    else if (QA.compareAndSet(a, k, t, null)) {
+                        BASE.setOpaque(this, b);
+                        return t;
                     }
                 }
-                else
-                    break;
             }
             return null;
         }
@@ -986,96 +942,59 @@
          * Takes next task, if one exists, in order specified by mode.
          */
         final ForkJoinTask<?> nextLocalTask() {
-            return (config < 0) ? poll() : pop();
+            ForkJoinTask<?> t = null;
+            int md = id, b, s, d, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                (d = (s = top) - (b = base)) > 0) {
+                if ((md & FIFO) == 0 || d == 1) {
+                    if ((t = (ForkJoinTask<?>)
+                         QA.getAndSet(a, (cap - 1) & --s, null)) != null)
+                        TOP.setOpaque(this, s);
+                }
+                else if ((t = (ForkJoinTask<?>)
+                          QA.getAndSet(a, (cap - 1) & b++, null)) != null) {
+                    BASE.setOpaque(this, b);
+                }
+                else // on contention in FIFO mode, use regular poll
+                    t = poll();
+            }
+            return t;
         }
 
         /**
          * Returns next task, if one exists, in order specified by mode.
          */
         final ForkJoinTask<?> peek() {
-            int al; ForkJoinTask<?>[] a;
-            return ((a = array) != null && (al = a.length) > 0) ?
-                a[(al - 1) & (config < 0 ? base : top - 1)] : null;
+            int cap; ForkJoinTask<?>[] a;
+            return ((a = array) != null && (cap = a.length) > 0) ?
+                a[(cap - 1) & ((id & FIFO) != 0 ? base : top - 1)] : null;
         }
 
         /**
          * Pops the given task only if it is at the current top.
          */
         final boolean tryUnpush(ForkJoinTask<?> task) {
-            int b = base, s = top, al; ForkJoinTask<?>[] a;
-            if ((a = array) != null && b != s && (al = a.length) > 0) {
-                int index = (al - 1) & --s;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                if (U.compareAndSwapObject(a, offset, task, null)) {
-                    top = s;
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        /**
-         * Shared version of push. Fails if already locked.
-         *
-         * @return status: > 0 locked, 0 possibly was empty, < 0 was nonempty
-         */
-        final int sharedPush(ForkJoinTask<?> task) {
-            int stat;
-            if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
-                int b = base, s = top, al, d; ForkJoinTask<?>[] a;
-                if ((a = array) != null && (al = a.length) > 0 &&
-                    al - 1 + (d = b - s) > 0) {
-                    a[(al - 1) & s] = task;
-                    top = s + 1;                 // relaxed writes OK here
-                    qlock = 0;
-                    stat = (d < 0 && b == base) ? d : 0;
-                }
-                else {
-                    growAndSharedPush(task);
-                    stat = 0;
-                }
-            }
-            else
-                stat = 1;
-            return stat;
-        }
-
-        /**
-         * Helper for sharedPush; called only when locked and resize
-         * needed.
-         */
-        private void growAndSharedPush(ForkJoinTask<?> task) {
-            try {
-                growArray();
-                int s = top, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && (al = a.length) > 0) {
-                    a[(al - 1) & s] = task;
-                    top = s + 1;
-                }
-            } finally {
-                qlock = 0;
-            }
+            boolean popped = false;
+            int s, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                (s = top) != base &&
+                (popped = QA.compareAndSet(a, (cap - 1) & --s, task, null)))
+                TOP.setOpaque(this, s);
+            return popped;
         }
 
         /**
          * Shared version of tryUnpush.
          */
-        final boolean trySharedUnpush(ForkJoinTask<?> task) {
+        final boolean tryLockedUnpush(ForkJoinTask<?> task) {
             boolean popped = false;
-            int s = top - 1, al; ForkJoinTask<?>[] a;
-            if ((a = array) != null && (al = a.length) > 0) {
-                int index = (al - 1) & s;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> t = (ForkJoinTask<?>) U.getObject(a, offset);
-                if (t == task &&
-                    U.compareAndSwapInt(this, QLOCK, 0, 1)) {
-                    if (top == s + 1 && array == a &&
-                        U.compareAndSwapObject(a, offset, task, null)) {
-                        popped = true;
-                        top = s;
-                    }
-                    U.putOrderedInt(this, QLOCK, 0);
-                }
+            int s = top - 1, k, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                a[k = (cap - 1) & s] == task && tryLockPhase()) {
+                if (top == s + 1 && array == a &&
+                    (popped = QA.compareAndSet(a, k, task, null)))
+                    top = s;
+                releasePhaseLock();
             }
             return popped;
         }
@@ -1084,252 +1003,150 @@
          * Removes and cancels all known tasks, ignoring any exceptions.
          */
         final void cancelAll() {
-            ForkJoinTask<?> t;
-            if ((t = currentJoin) != null) {
-                currentJoin = null;
-                ForkJoinTask.cancelIgnoringExceptions(t);
-            }
-            if ((t = currentSteal) != null) {
-                currentSteal = null;
-                ForkJoinTask.cancelIgnoringExceptions(t);
-            }
-            while ((t = poll()) != null)
+            for (ForkJoinTask<?> t; (t = poll()) != null; )
                 ForkJoinTask.cancelIgnoringExceptions(t);
         }
 
         // Specialized execution methods
 
         /**
-         * Pops and executes up to POLL_LIMIT tasks or until empty.
+         * Runs the given (stolen) task if nonnull, as well as
+         * remaining local tasks and others available from the given
+         * queue, up to bound n (to avoid infinite unfairness).
          */
-        final void localPopAndExec() {
-            for (int nexec = 0;;) {
-                int b = base, s = top, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && b != s && (al = a.length) > 0) {
-                    int index = (al - 1) & --s;
-                    long offset = ((long)index << ASHIFT) + ABASE;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        U.getAndSetObject(a, offset, null);
-                    if (t != null) {
-                        top = s;
-                        (currentSteal = t).doExec();
-                        if (++nexec > POLL_LIMIT)
-                            break;
-                    }
-                    else
+        final void topLevelExec(ForkJoinTask<?> t, WorkQueue q, int n) {
+            if (t != null && q != null) { // hoist checks
+                int nstolen = 1;
+                for (;;) {
+                    t.doExec();
+                    if (n-- < 0)
                         break;
-                }
-                else
-                    break;
-            }
-        }
-
-        /**
-         * Polls and executes up to POLL_LIMIT tasks or until empty.
-         */
-        final void localPollAndExec() {
-            for (int nexec = 0;;) {
-                int b = base, s = top, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && b != s && (al = a.length) > 0) {
-                    int index = (al - 1) & b++;
-                    long offset = ((long)index << ASHIFT) + ABASE;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        U.getAndSetObject(a, offset, null);
-                    if (t != null) {
-                        base = b;
-                        t.doExec();
-                        if (++nexec > POLL_LIMIT)
+                    else if ((t = nextLocalTask()) == null) {
+                        if ((t = q.poll()) == null)
                             break;
+                        else
+                            ++nstolen;
                     }
                 }
-                else
-                    break;
-            }
-        }
-
-        /**
-         * Executes the given task and (some) remaining local tasks.
-         */
-        final void runTask(ForkJoinTask<?> task) {
-            if (task != null) {
-                task.doExec();
-                if (config < 0)
-                    localPollAndExec();
-                else
-                    localPopAndExec();
-                int ns = ++nsteals;
                 ForkJoinWorkerThread thread = owner;
-                currentSteal = null;
-                if (ns < 0)           // collect on overflow
-                    transferStealCount(pool);
+                nsteals += nstolen;
+                source = 0;
                 if (thread != null)
                     thread.afterTopLevelExec();
             }
         }
 
         /**
-         * Adds steal count to pool steal count if it exists, and resets.
+         * If present, removes task from queue and executes it.
          */
-        final void transferStealCount(ForkJoinPool p) {
-            AuxState aux;
-            if (p != null && (aux = p.auxState) != null) {
-                long s = nsteals;
-                nsteals = 0;            // if negative, correct for overflow
-                if (s < 0) s = Integer.MAX_VALUE;
-                aux.lock();
-                try {
-                    aux.stealCount += s;
-                } finally {
-                    aux.unlock();
-                }
-            }
-        }
-
-        /**
-         * If present, removes from queue and executes the given task,
-         * or any other cancelled task. Used only by awaitJoin.
-         *
-         * @return true if queue empty and task not known to be done
-         */
-        final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
-            if (task != null && task.status >= 0) {
-                int b, s, d, al; ForkJoinTask<?>[] a;
-                while ((d = (b = base) - (s = top)) < 0 &&
-                       (a = array) != null && (al = a.length) > 0) {
-                    for (;;) {      // traverse from s to b
-                        int index = --s & (al - 1);
-                        long offset = (index << ASHIFT) + ABASE;
-                        ForkJoinTask<?> t = (ForkJoinTask<?>)
-                            U.getObjectVolatile(a, offset);
-                        if (t == null)
-                            break;                   // restart
-                        else if (t == task) {
-                            boolean removed = false;
-                            if (s + 1 == top) {      // pop
-                                if (U.compareAndSwapObject(a, offset, t, null)) {
-                                    top = s;
-                                    removed = true;
-                                }
+        final void tryRemoveAndExec(ForkJoinTask<?> task) {
+            ForkJoinTask<?>[] a; int s, cap;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                (s = top) - base > 0) { // traverse from top
+                for (int m = cap - 1, ns = s - 1, i = ns; ; --i) {
+                    int index = i & m;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)QA.get(a, index);
+                    if (t == null)
+                        break;
+                    else if (t == task) {
+                        if (QA.compareAndSet(a, index, t, null)) {
+                            top = ns;   // safely shift down
+                            for (int j = i; j != ns; ++j) {
+                                ForkJoinTask<?> f;
+                                int pindex = (j + 1) & m;
+                                f = (ForkJoinTask<?>)QA.get(a, pindex);
+                                QA.setVolatile(a, pindex, null);
+                                int jindex = j & m;
+                                QA.setRelease(a, jindex, f);
                             }
-                            else if (base == b)      // replace with proxy
-                                removed = U.compareAndSwapObject(a, offset, t,
-                                                                 new EmptyTask());
-                            if (removed) {
-                                ForkJoinTask<?> ps = currentSteal;
-                                (currentSteal = task).doExec();
-                                currentSteal = ps;
-                            }
-                            break;
+                            VarHandle.releaseFence();
+                            t.doExec();
                         }
-                        else if (t.status < 0 && s + 1 == top) {
-                            if (U.compareAndSwapObject(a, offset, t, null)) {
-                                top = s;
-                            }
-                            break;                  // was cancelled
-                        }
-                        else if (++d == 0) {
-                            if (base != b)          // rescan
-                                break;
-                            return false;
-                        }
+                        break;
                     }
-                    if (task.status < 0)
-                        return false;
                 }
             }
-            return true;
         }
 
         /**
-         * Pops task if in the same CC computation as the given task,
-         * in either shared or owned mode. Used only by helpComplete.
+         * Tries to pop and run tasks within the target's computation
+         * until done, not found, or limit exceeded.
+         *
+         * @param task root of CountedCompleter computation
+         * @param limit max runs, or zero for no limit
+         * @param shared true if must lock to extract task
+         * @return task status on exit
          */
-        final CountedCompleter<?> popCC(CountedCompleter<?> task, int mode) {
-            int b = base, s = top, al; ForkJoinTask<?>[] a;
-            if ((a = array) != null && b != s && (al = a.length) > 0) {
-                int index = (al - 1) & (s - 1);
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> o = (ForkJoinTask<?>)
-                    U.getObjectVolatile(a, offset);
-                if (o instanceof CountedCompleter) {
-                    CountedCompleter<?> t = (CountedCompleter<?>)o;
-                    for (CountedCompleter<?> r = t;;) {
-                        if (r == task) {
-                            if ((mode & IS_OWNED) == 0) {
-                                boolean popped = false;
-                                if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+        final int helpCC(CountedCompleter<?> task, int limit, boolean shared) {
+            int status = 0;
+            if (task != null && (status = task.status) >= 0) {
+                int s, k, cap; ForkJoinTask<?>[] a;
+                while ((a = array) != null && (cap = a.length) > 0 &&
+                       (s = top) - base > 0) {
+                    CountedCompleter<?> v = null;
+                    ForkJoinTask<?> o = a[k = (cap - 1) & (s - 1)];
+                    if (o instanceof CountedCompleter) {
+                        CountedCompleter<?> t = (CountedCompleter<?>)o;
+                        for (CountedCompleter<?> f = t;;) {
+                            if (f != task) {
+                                if ((f = f.completer) == null)
+                                    break;
+                            }
+                            else if (shared) {
+                                if (tryLockPhase()) {
                                     if (top == s && array == a &&
-                                        U.compareAndSwapObject(a, offset,
-                                                               t, null)) {
-                                        popped = true;
+                                        QA.compareAndSet(a, k, t, null)) {
                                         top = s - 1;
+                                        v = t;
                                     }
-                                    U.putOrderedInt(this, QLOCK, 0);
-                                    if (popped)
-                                        return t;
+                                    releasePhaseLock();
                                 }
+                                break;
                             }
-                            else if (U.compareAndSwapObject(a, offset,
-                                                            t, null)) {
-                                top = s - 1;
-                                return t;
+                            else {
+                                if (QA.compareAndSet(a, k, t, null)) {
+                                    top = s - 1;
+                                    v = t;
+                                }
+                                break;
                             }
-                            break;
                         }
-                        else if ((r = r.completer) == null) // try parent
-                            break;
                     }
+                    if (v != null)
+                        v.doExec();
+                    if ((status = task.status) < 0 || v == null ||
+                        (limit != 0 && --limit == 0))
+                        break;
                 }
             }
-            return null;
+            return status;
         }
 
         /**
-         * Steals and runs a task in the same CC computation as the
-         * given task if one exists and can be taken without
-         * contention. Otherwise returns a checksum/control value for
-         * use by method helpComplete.
+         * Tries to poll and run AsynchronousCompletionTasks until
+         * none found or blocker is released
          *
-         * @return 1 if successful, 2 if retryable (lost to another
-         * stealer), -1 if non-empty but no matching task found, else
-         * the base index, forced negative.
+         * @param blocker the blocker
          */
-        final int pollAndExecCC(CountedCompleter<?> task) {
-            ForkJoinTask<?>[] a;
-            int b = base, s = top, al, h;
-            if ((a = array) != null && b != s && (al = a.length) > 0) {
-                int index = (al - 1) & b;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> o = (ForkJoinTask<?>)
-                    U.getObjectVolatile(a, offset);
-                if (o == null)
-                    h = 2;                      // retryable
-                else if (!(o instanceof CountedCompleter))
-                    h = -1;                     // unmatchable
-                else {
-                    CountedCompleter<?> t = (CountedCompleter<?>)o;
-                    for (CountedCompleter<?> r = t;;) {
-                        if (r == task) {
-                            if (b++ == base &&
-                                U.compareAndSwapObject(a, offset, t, null)) {
-                                base = b;
-                                t.doExec();
-                                h = 1;          // success
-                            }
-                            else
-                                h = 2;          // lost CAS
+        final void helpAsyncBlocker(ManagedBlocker blocker) {
+            if (blocker != null) {
+                int b, k, cap; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+                while ((a = array) != null && (cap = a.length) > 0 &&
+                       top - (b = base) > 0) {
+                    t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
+                    if (blocker.isReleasable())
+                        break;
+                    else if (base == b++ && t != null) {
+                        if (!(t instanceof CompletableFuture.
+                              AsynchronousCompletionTask))
                             break;
-                        }
-                        else if ((r = r.completer) == null) {
-                            h = -1;             // unmatched
-                            break;
+                        else if (QA.compareAndSet(a, k, t, null)) {
+                            BASE.setOpaque(this, b);
+                            t.doExec();
                         }
                     }
                 }
             }
-            else
-                h = b | Integer.MIN_VALUE;      // to sense movement on re-poll
-            return h;
         }
 
         /**
@@ -1337,29 +1154,24 @@
          */
         final boolean isApparentlyUnblocked() {
             Thread wt; Thread.State s;
-            return (scanState >= 0 &&
-                    (wt = owner) != null &&
+            return ((wt = owner) != null &&
                     (s = wt.getState()) != Thread.State.BLOCKED &&
                     s != Thread.State.WAITING &&
                     s != Thread.State.TIMED_WAITING);
         }
 
-        // Unsafe mechanics. Note that some are (and must be) the same as in FJP
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-        private static final long QLOCK;
-        private static final int ABASE;
-        private static final int ASHIFT;
+        // VarHandle mechanics.
+        static final VarHandle PHASE;
+        static final VarHandle BASE;
+        static final VarHandle TOP;
         static {
             try {
-                QLOCK = U.objectFieldOffset
-                    (WorkQueue.class.getDeclaredField("qlock"));
-                ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
-                int scale = U.arrayIndexScale(ForkJoinTask[].class);
-                if ((scale & (scale - 1)) != 0)
-                    throw new Error("array index scale not a power of two");
-                ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                PHASE = l.findVarHandle(WorkQueue.class, "phase", int.class);
+                BASE = l.findVarHandle(WorkQueue.class, "base", int.class);
+                TOP = l.findVarHandle(WorkQueue.class, "top", int.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
         }
     }
@@ -1375,7 +1187,7 @@
 
     /**
      * Permission required for callers of methods that may start or
-     * kill threads.  Also used as a static lock in tryInitialize.
+     * kill threads.
      */
     static final RuntimePermission modifyThreadPermission;
 
@@ -1416,18 +1228,15 @@
     // static configuration constants
 
     /**
-     * Initial timeout value (in milliseconds) for the thread
-     * triggering quiescence to park waiting for new work. On timeout,
-     * the thread will instead try to shrink the number of workers.
-     * The value should be large enough to avoid overly aggressive
-     * shrinkage during most transient stalls (long GCs etc).
+     * Default idle timeout value (in milliseconds) for the thread
+     * triggering quiescence to park waiting for new work
      */
-    private static final long IDLE_TIMEOUT_MS = 2000L; // 2sec
+    private static final long DEFAULT_KEEPALIVE = 60_000L;
 
     /**
-     * Tolerance for idle timeouts, to cope with timer undershoots.
+     * Undershoot tolerance for idle timeouts
      */
-    private static final long TIMEOUT_SLOP_MS =   20L; // 20ms
+    private static final long TIMEOUT_SLOP = 20L;
 
     /**
      * The default value for COMMON_MAX_SPARES.  Overridable using the
@@ -1447,7 +1256,7 @@
 
     /*
      * Bits and masks for field ctl, packed with 4 16 bit subfields:
-     * AC: Number of active running workers minus target parallelism
+     * RC: Number of released (unqueued) workers minus target parallelism
      * TC: Number of total workers minus target parallelism
      * SS: version count and status of top waiting thread
      * ID: poolIndex of top of Treiber stack of waiters
@@ -1456,26 +1265,30 @@
      * (including version bits) as sp=(int)ctl.  The offsets of counts
      * by the target parallelism and the positionings of fields makes
      * it possible to perform the most common checks via sign tests of
-     * fields: When ac is negative, there are not enough active
+     * fields: When ac is negative, there are not enough unqueued
      * workers, when tc is negative, there are not enough total
      * workers.  When sp is non-zero, there are waiting workers.  To
      * deal with possibly negative fields, we use casts in and out of
      * "short" and/or signed shifts to maintain signedness.
      *
-     * Because it occupies uppermost bits, we can add one active count
-     * using getAndAddLong of AC_UNIT, rather than CAS, when returning
+     * Because it occupies uppermost bits, we can add one release count
+     * using getAndAddLong of RC_UNIT, rather than CAS, when returning
      * from a blocked join.  Other updates entail multiple subfields
      * and masking, requiring CAS.
+     *
+     * The limits packed in field "bounds" are also offset by the
+     * parallelism level to make them comparable to the ctl rc and tc
+     * fields.
      */
 
     // Lower and upper word masks
     private static final long SP_MASK    = 0xffffffffL;
     private static final long UC_MASK    = ~SP_MASK;
 
-    // Active counts
-    private static final int  AC_SHIFT   = 48;
-    private static final long AC_UNIT    = 0x0001L << AC_SHIFT;
-    private static final long AC_MASK    = 0xffffL << AC_SHIFT;
+    // Release counts
+    private static final int  RC_SHIFT   = 48;
+    private static final long RC_UNIT    = 0x0001L << RC_SHIFT;
+    private static final long RC_MASK    = 0xffffL << RC_SHIFT;
 
     // Total counts
     private static final int  TC_SHIFT   = 32;
@@ -1483,52 +1296,21 @@
     private static final long TC_MASK    = 0xffffL << TC_SHIFT;
     private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
 
-    // runState bits: SHUTDOWN must be negative, others arbitrary powers of two
-    private static final int  STARTED    = 1;
-    private static final int  STOP       = 1 << 1;
-    private static final int  TERMINATED = 1 << 2;
-    private static final int  SHUTDOWN   = 1 << 31;
-
     // Instance fields
-    volatile long ctl;                   // main pool control
-    volatile int runState;
-    final int config;                    // parallelism, mode
-    AuxState auxState;                   // lock, steal counts
-    volatile WorkQueue[] workQueues;     // main registry
-    final String workerNamePrefix;       // to create worker name string
+
+    volatile long stealCount;            // collects worker nsteals
+    final long keepAlive;                // milliseconds before dropping if idle
+    int indexSeed;                       // next worker index
+    final int bounds;                    // min, max threads packed as shorts
+    volatile int mode;                   // parallelism, runstate, queue mode
+    WorkQueue[] workQueues;              // main registry
+    final String workerNamePrefix;       // for worker thread string; sync lock
     final ForkJoinWorkerThreadFactory factory;
     final UncaughtExceptionHandler ueh;  // per-worker UEH
+    final Predicate<? super ForkJoinPool> saturate;
 
-    /**
-     * Instantiates fields upon first submission, or upon shutdown if
-     * no submissions. If checkTermination true, also responds to
-     * termination by external calls submitting tasks.
-     */
-    private void tryInitialize(boolean checkTermination) {
-        if (runState == 0) { // bootstrap by locking static field
-            int p = config & SMASK;
-            int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots
-            n |= n >>> 1;    // create workQueues array with size a power of two
-            n |= n >>> 2;
-            n |= n >>> 4;
-            n |= n >>> 8;
-            n |= n >>> 16;
-            n = ((n + 1) << 1) & SMASK;
-            AuxState aux = new AuxState();
-            WorkQueue[] ws = new WorkQueue[n];
-            synchronized (modifyThreadPermission) { // double-check
-                if (runState == 0) {
-                    workQueues = ws;
-                    auxState = aux;
-                    runState = STARTED;
-                }
-            }
-        }
-        if (checkTermination && runState < 0) {
-            tryTerminate(false, false); // help terminate
-            throw new RejectedExecutionException();
-        }
-    }
+    @jdk.internal.vm.annotation.Contended("fjpctl") // segregate
+    volatile long ctl;                   // main pool control
 
     // Creating, registering and deregistering workers
 
@@ -1537,18 +1319,14 @@
      * count has already been incremented as a reservation.  Invokes
      * deregisterWorker on any failure.
      *
-     * @param isSpare true if this is a spare thread
      * @return true if successful
      */
-    private boolean createWorker(boolean isSpare) {
+    private boolean createWorker() {
         ForkJoinWorkerThreadFactory fac = factory;
         Throwable ex = null;
         ForkJoinWorkerThread wt = null;
-        WorkQueue q;
         try {
             if (fac != null && (wt = fac.newThread(this)) != null) {
-                if (isSpare && (q = wt.workQueue) != null)
-                    q.config |= SPARE_WORKER;
                 wt.start();
                 return true;
             }
@@ -1569,10 +1347,10 @@
      */
     private void tryAddWorker(long c) {
         do {
-            long nc = ((AC_MASK & (c + AC_UNIT)) |
+            long nc = ((RC_MASK & (c + RC_UNIT)) |
                        (TC_MASK & (c + TC_UNIT)));
-            if (ctl == c && U.compareAndSwapLong(this, CTL, c, nc)) {
-                createWorker(false);
+            if (ctl == c && CTL.compareAndSet(this, c, nc)) {
+                createWorker();
                 break;
             }
         } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
@@ -1587,41 +1365,55 @@
      */
     final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
         UncaughtExceptionHandler handler;
-        AuxState aux;
-        wt.setDaemon(true);                           // configure thread
+        wt.setDaemon(true);                             // configure thread
         if ((handler = ueh) != null)
             wt.setUncaughtExceptionHandler(handler);
+        int tid = 0;                                    // for thread name
+        int idbits = mode & FIFO;
+        String prefix = workerNamePrefix;
         WorkQueue w = new WorkQueue(this, wt);
-        int i = 0;                                    // assign a pool index
-        int mode = config & MODE_MASK;
-        if ((aux = auxState) != null) {
-            aux.lock();
-            try {
-                int s = (int)(aux.indexSeed += SEED_INCREMENT), n, m;
-                WorkQueue[] ws = workQueues;
-                if (ws != null && (n = ws.length) > 0) {
-                    i = (m = n - 1) & ((s << 1) | 1); // odd-numbered indices
-                    if (ws[i] != null) {              // collision
-                        int probes = 0;               // step by approx half n
-                        int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
-                        while (ws[i = (i + step) & m] != null) {
-                            if (++probes >= n) {
-                                workQueues = ws = Arrays.copyOf(ws, n <<= 1);
-                                m = n - 1;
-                                probes = 0;
-                            }
+        if (prefix != null) {
+            synchronized (prefix) {
+                WorkQueue[] ws = workQueues; int n;
+                int s = indexSeed += SEED_INCREMENT;
+                idbits |= (s & ~(SMASK | FIFO | DORMANT));
+                if (ws != null && (n = ws.length) > 1) {
+                    int m = n - 1;
+                    tid = m & ((s << 1) | 1);           // odd-numbered indices
+                    for (int probes = n >>> 1;;) {      // find empty slot
+                        WorkQueue q;
+                        if ((q = ws[tid]) == null || q.phase == QUIET)
+                            break;
+                        else if (--probes == 0) {
+                            tid = n | 1;                // resize below
+                            break;
                         }
+                        else
+                            tid = (tid + 2) & m;
                     }
-                    w.hint = s;                       // use as random seed
-                    w.config = i | mode;
-                    w.scanState = i | (s & 0x7fff0000); // random seq bits
-                    ws[i] = w;
+                    w.phase = w.id = tid | idbits;      // now publishable
+
+                    if (tid < n)
+                        ws[tid] = w;
+                    else {                              // expand array
+                        int an = n << 1;
+                        WorkQueue[] as = new WorkQueue[an];
+                        as[tid] = w;
+                        int am = an - 1;
+                        for (int j = 0; j < n; ++j) {
+                            WorkQueue v;                // copy external queue
+                            if ((v = ws[j]) != null)    // position may change
+                                as[v.id & am & SQMASK] = v;
+                            if (++j >= n)
+                                break;
+                            as[j] = ws[j];              // copy worker
+                        }
+                        workQueues = as;
+                    }
                 }
-            } finally {
-                aux.unlock();
             }
+            wt.setName(prefix.concat(Integer.toString(tid)));
         }
-        wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
         return w;
     }
 
@@ -1636,64 +1428,48 @@
      */
     final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
         WorkQueue w = null;
+        int phase = 0;
         if (wt != null && (w = wt.workQueue) != null) {
-            AuxState aux; WorkQueue[] ws;          // remove index from array
-            int idx = w.config & SMASK;
-            int ns = w.nsteals;
-            if ((aux = auxState) != null) {
-                aux.lock();
-                try {
-                    if ((ws = workQueues) != null && ws.length > idx &&
-                        ws[idx] == w)
-                        ws[idx] = null;
-                    aux.stealCount += ns;
-                } finally {
-                    aux.unlock();
+            Object lock = workerNamePrefix;
+            int wid = w.id;
+            long ns = (long)w.nsteals & 0xffffffffL;
+            if (lock != null) {
+                synchronized (lock) {
+                    WorkQueue[] ws; int n, i;         // remove index from array
+                    if ((ws = workQueues) != null && (n = ws.length) > 0 &&
+                        ws[i = wid & (n - 1)] == w)
+                        ws[i] = null;
+                    stealCount += ns;
                 }
             }
+            phase = w.phase;
         }
-        if (w == null || (w.config & UNREGISTERED) == 0) { // else pre-adjusted
+        if (phase != QUIET) {                         // else pre-adjusted
             long c;                                   // decrement counts
-            do {} while (!U.compareAndSwapLong
-                         (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
-                                               (TC_MASK & (c - TC_UNIT)) |
-                                               (SP_MASK & c))));
+            do {} while (!CTL.weakCompareAndSet
+                         (this, c = ctl, ((RC_MASK & (c - RC_UNIT)) |
+                                          (TC_MASK & (c - TC_UNIT)) |
+                                          (SP_MASK & c))));
         }
-        if (w != null) {
-            w.currentSteal = null;
-            w.qlock = -1;                             // ensure set
+        if (w != null)
             w.cancelAll();                            // cancel remaining tasks
-        }
-        while (tryTerminate(false, false) >= 0) {     // possibly replace
-            WorkQueue[] ws; int wl, sp; long c;
-            if (w == null || w.array == null ||
-                (ws = workQueues) == null || (wl = ws.length) <= 0)
-                break;
-            else if ((sp = (int)(c = ctl)) != 0) {    // wake up replacement
-                if (tryRelease(c, ws[(wl - 1) & sp], AC_UNIT))
-                    break;
-            }
-            else if (ex != null && (c & ADD_WORKER) != 0L) {
-                tryAddWorker(c);                      // create replacement
-                break;
-            }
-            else                                      // don't need replacement
-                break;
-        }
+
+        if (!tryTerminate(false, false) &&            // possibly replace worker
+            w != null && w.array != null)             // avoid repeated failures
+            signalWork();
+
         if (ex == null)                               // help clean on way out
             ForkJoinTask.helpExpungeStaleExceptions();
         else                                          // rethrow
             ForkJoinTask.rethrow(ex);
     }
 
-    // Signalling
-
     /**
-     * Tries to create or activate a worker if too few are active.
+     * Tries to create or release a worker if too few are running.
      */
     final void signalWork() {
         for (;;) {
-            long c; int sp, i; WorkQueue v; WorkQueue[] ws;
+            long c; int sp; WorkQueue[] ws; int i; WorkQueue v;
             if ((c = ctl) >= 0L)                      // enough workers
                 break;
             else if ((sp = (int)c) == 0) {            // no idle workers
@@ -1708,12 +1484,14 @@
             else if ((v = ws[i]) == null)
                 break;                                // terminating
             else {
-                int ns = sp & ~UNSIGNALLED;
-                int vs = v.scanState;
-                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
-                if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
-                    v.scanState = ns;
-                    LockSupport.unpark(v.parker);
+                int np = sp & ~UNSIGNALLED;
+                int vp = v.phase;
+                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + RC_UNIT));
+                Thread vt = v.owner;
+                if (sp == vp && CTL.compareAndSet(this, c, nc)) {
+                    v.phase = np;
+                    if (vt != null && v.source < 0)
+                        LockSupport.unpark(vt);
                     break;
                 }
             }
@@ -1721,502 +1499,181 @@
     }
 
     /**
-     * Signals and releases worker v if it is top of idle worker
-     * stack.  This performs a one-shot version of signalWork only if
-     * there is (apparently) at least one idle worker.
+     * Tries to decrement counts (sometimes implicitly) and possibly
+     * arrange for a compensating worker in preparation for blocking:
+     * If not all core workers yet exist, creates one, else if any are
+     * unreleased (possibly including caller) releases one, else if
+     * fewer than the minimum allowed number of workers running,
+     * checks to see that they are all active, and if so creates an
+     * extra worker unless over maximum limit and policy is to
+     * saturate.  Most of these steps can fail due to interference, in
+     * which case 0 is returned so caller will retry. A negative
+     * return value indicates that the caller doesn't need to
+     * re-adjust counts when later unblocked.
      *
-     * @param c incoming ctl value
-     * @param v if non-null, a worker
-     * @param inc the increment to active count (zero when compensating)
-     * @return true if successful
+     * @return 1: block then adjust, -1: block without adjust, 0 : retry
      */
-    private boolean tryRelease(long c, WorkQueue v, long inc) {
-        int sp = (int)c, ns = sp & ~UNSIGNALLED;
-        if (v != null) {
-            int vs = v.scanState;
-            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + inc));
-            if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
-                v.scanState = ns;
-                LockSupport.unpark(v.parker);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * With approx probability of a missed signal, tries (once) to
-     * reactivate worker w (or some other worker), failing if stale or
-     * known to be already active.
-     *
-     * @param w the worker
-     * @param ws the workQueue array to use
-     * @param r random seed
-     */
-    private void tryReactivate(WorkQueue w, WorkQueue[] ws, int r) {
-        long c; int sp, wl; WorkQueue v;
-        if ((sp = (int)(c = ctl)) != 0 && w != null &&
-            ws != null && (wl = ws.length) > 0 &&
-            ((sp ^ r) & SS_SEQ) == 0 &&
-            (v = ws[(wl - 1) & sp]) != null) {
-            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
-            int ns = sp & ~UNSIGNALLED;
-            if (w.scanState < 0 &&
-                v.scanState == sp &&
-                U.compareAndSwapLong(this, CTL, c, nc)) {
-                v.scanState = ns;
-                LockSupport.unpark(v.parker);
-            }
-        }
-    }
-
-    /**
-     * If worker w exists and is active, enqueues and sets status to inactive.
-     *
-     * @param w the worker
-     * @param ss current (non-negative) scanState
-     */
-    private void inactivate(WorkQueue w, int ss) {
-        int ns = (ss + SS_SEQ) | UNSIGNALLED;
-        long lc = ns & SP_MASK, nc, c;
-        if (w != null) {
-            w.scanState = ns;
-            do {
-                nc = lc | (UC_MASK & ((c = ctl) - AC_UNIT));
-                w.stackPred = (int)c;
-            } while (!U.compareAndSwapLong(this, CTL, c, nc));
-        }
-    }
-
-    /**
-     * Possibly blocks worker w waiting for signal, or returns
-     * negative status if the worker should terminate. May return
-     * without status change if multiple stale unparks and/or
-     * interrupts occur.
-     *
-     * @param w the calling worker
-     * @return negative if w should terminate
-     */
-    private int awaitWork(WorkQueue w) {
-        int stat = 0;
-        if (w != null && w.scanState < 0) {
-            long c = ctl;
-            if ((int)(c >> AC_SHIFT) + (config & SMASK) <= 0)
-                stat = timedAwaitWork(w, c);     // possibly quiescent
-            else if ((runState & STOP) != 0)
-                stat = w.qlock = -1;             // pool terminating
-            else if (w.scanState < 0) {
-                w.parker = Thread.currentThread();
-                if (w.scanState < 0)             // recheck after write
-                    LockSupport.park(this);
-                w.parker = null;
-                if ((runState & STOP) != 0)
-                    stat = w.qlock = -1;         // recheck
-                else if (w.scanState < 0)
-                    Thread.interrupted();        // clear status
-            }
-        }
-        return stat;
-    }
-
-    /**
-     * Possibly triggers shutdown and tries (once) to block worker
-     * when pool is (or may be) quiescent. Waits up to a duration
-     * determined by number of workers.  On timeout, if ctl has not
-     * changed, terminates the worker, which will in turn wake up
-     * another worker to possibly repeat this process.
-     *
-     * @param w the calling worker
-     * @return negative if w should terminate
-     */
-    private int timedAwaitWork(WorkQueue w, long c) {
-        int stat = 0;
-        int scale = 1 - (short)(c >>> TC_SHIFT);
-        long deadline = (((scale <= 0) ? 1 : scale) * IDLE_TIMEOUT_MS +
-                         System.currentTimeMillis());
-        if ((runState >= 0 || (stat = tryTerminate(false, false)) > 0) &&
-            w != null && w.scanState < 0) {
-            int ss; AuxState aux;
-            w.parker = Thread.currentThread();
-            if (w.scanState < 0)
-                LockSupport.parkUntil(this, deadline);
-            w.parker = null;
-            if ((runState & STOP) != 0)
-                stat = w.qlock = -1;         // pool terminating
-            else if ((ss = w.scanState) < 0 && !Thread.interrupted() &&
-                     (int)c == ss && (aux = auxState) != null && ctl == c &&
-                     deadline - System.currentTimeMillis() <= TIMEOUT_SLOP_MS) {
-                aux.lock();
-                try {                        // pre-deregister
-                    WorkQueue[] ws;
-                    int cfg = w.config, idx = cfg & SMASK;
-                    long nc = ((UC_MASK & (c - TC_UNIT)) |
-                               (SP_MASK & w.stackPred));
-                    if ((runState & STOP) == 0 &&
-                        (ws = workQueues) != null &&
-                        idx < ws.length && idx >= 0 && ws[idx] == w &&
-                        U.compareAndSwapLong(this, CTL, c, nc)) {
-                        ws[idx] = null;
-                        w.config = cfg | UNREGISTERED;
-                        stat = w.qlock = -1;
+    private int tryCompensate(WorkQueue w) {
+        int t, n, sp;
+        long c = ctl;
+        WorkQueue[] ws = workQueues;
+        if ((t = (short)(c >>> TC_SHIFT)) >= 0) {
+            if (ws == null || (n = ws.length) <= 0 || w == null)
+                return 0;                        // disabled
+            else if ((sp = (int)c) != 0) {       // replace or release
+                WorkQueue v = ws[sp & (n - 1)];
+                int wp = w.phase;
+                long uc = UC_MASK & ((wp < 0) ? c + RC_UNIT : c);
+                int np = sp & ~UNSIGNALLED;
+                if (v != null) {
+                    int vp = v.phase;
+                    Thread vt = v.owner;
+                    long nc = ((long)v.stackPred & SP_MASK) | uc;
+                    if (vp == sp && CTL.compareAndSet(this, c, nc)) {
+                        v.phase = np;
+                        if (vt != null && v.source < 0)
+                            LockSupport.unpark(vt);
+                        return (wp < 0) ? -1 : 1;
                     }
-                } finally {
-                    aux.unlock();
                 }
+                return 0;
             }
-        }
-        return stat;
-    }
-
-    /**
-     * If the given worker is a spare with no queued tasks, and there
-     * are enough existing workers, drops it from ctl counts and sets
-     * its state to terminated.
-     *
-     * @param w the calling worker -- must be a spare
-     * @return true if dropped (in which case it must not process more tasks)
-     */
-    private boolean tryDropSpare(WorkQueue w) {
-        if (w != null && w.isEmpty()) {           // no local tasks
-            long c; int sp, wl; WorkQueue[] ws; WorkQueue v;
-            while ((short)((c = ctl) >> TC_SHIFT) > 0 &&
-                   ((sp = (int)c) != 0 || (int)(c >> AC_SHIFT) > 0) &&
-                   (ws = workQueues) != null && (wl = ws.length) > 0) {
-                boolean dropped, canDrop;
-                if (sp == 0) {                    // no queued workers
-                    long nc = ((AC_MASK & (c - AC_UNIT)) |
-                               (TC_MASK & (c - TC_UNIT)) | (SP_MASK & c));
-                    dropped = U.compareAndSwapLong(this, CTL, c, nc);
+            else if ((int)(c >> RC_SHIFT) -      // reduce parallelism
+                     (short)(bounds & SMASK) > 0) {
+                long nc = ((RC_MASK & (c - RC_UNIT)) | (~RC_MASK & c));
+                return CTL.compareAndSet(this, c, nc) ? 1 : 0;
+            }
+            else {                               // validate
+                int md = mode, pc = md & SMASK, tc = pc + t, bc = 0;
+                boolean unstable = false;
+                for (int i = 1; i < n; i += 2) {
+                    WorkQueue q; Thread wt; Thread.State ts;
+                    if ((q = ws[i]) != null) {
+                        if (q.source == 0) {
+                            unstable = true;
+                            break;
+                        }
+                        else {
+                            --tc;
+                            if ((wt = q.owner) != null &&
+                                ((ts = wt.getState()) == Thread.State.BLOCKED ||
+                                 ts == Thread.State.WAITING))
+                                ++bc;            // worker is blocking
+                        }
+                    }
                 }
-                else if (
-                    (v = ws[(wl - 1) & sp]) == null || v.scanState != sp)
-                    dropped = false;              // stale; retry
-                else {
-                    long nc = v.stackPred & SP_MASK;
-                    if (w == v || w.scanState >= 0) {
-                        canDrop = true;           // w unqueued or topmost
-                        nc |= ((AC_MASK & c) |    // ensure replacement
-                               (TC_MASK & (c - TC_UNIT)));
-                    }
-                    else {                        // w may be queued
-                        canDrop = false;          // help uncover
-                        nc |= ((AC_MASK & (c + AC_UNIT)) |
-                               (TC_MASK & c));
-                    }
-                    if (U.compareAndSwapLong(this, CTL, c, nc)) {
-                        v.scanState = sp & ~UNSIGNALLED;
-                        LockSupport.unpark(v.parker);
-                        dropped = canDrop;
+                if (unstable || tc != 0 || ctl != c)
+                    return 0;                    // inconsistent
+                else if (t + pc >= MAX_CAP || t >= (bounds >>> SWIDTH)) {
+                    Predicate<? super ForkJoinPool> sat;
+                    if ((sat = saturate) != null && sat.test(this))
+                        return -1;
+                    else if (bc < pc) {          // lagging
+                        Thread.yield();          // for retry spins
+                        return 0;
                     }
                     else
-                        dropped = false;
-                }
-                if (dropped) {                    // pre-deregister
-                    int cfg = w.config, idx = cfg & SMASK;
-                    if (idx >= 0 && idx < ws.length && ws[idx] == w)
-                        ws[idx] = null;
-                    w.config = cfg | UNREGISTERED;
-                    w.qlock = -1;
-                    return true;
+                        throw new RejectedExecutionException(
+                            "Thread limit exceeded replacing blocked worker");
                 }
             }
         }
-        return false;
+
+        long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); // expand pool
+        return CTL.compareAndSet(this, c, nc) && createWorker() ? 1 : 0;
     }
 
     /**
      * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
+     * See above for explanation.
      */
     final void runWorker(WorkQueue w) {
-        w.growArray();                                  // allocate queue
-        int bound = (w.config & SPARE_WORKER) != 0 ? 0 : POLL_LIMIT;
-        long seed = w.hint * 0xdaba0b6eb09322e3L;       // initial random seed
-        if ((runState & STOP) == 0) {
-            for (long r = (seed == 0L) ? 1L : seed;;) { // ensure nonzero
-                if (bound == 0 && tryDropSpare(w))
-                    break;
-                // high bits of prev seed for step; current low bits for idx
-                int step = (int)(r >>> 48) | 1;
-                r ^= r >>> 12; r ^= r << 25; r ^= r >>> 27; // xorshift
-                if (scan(w, bound, step, (int)r) < 0 && awaitWork(w) < 0)
-                    break;
+        int r = (w.id ^ ThreadLocalRandom.nextSecondarySeed()) | FIFO; // rng
+        w.array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; // initialize
+        for (;;) {
+            int phase;
+            if (scan(w, r)) {                     // scan until apparently empty
+                r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // move (xorshift)
             }
-        }
-    }
-
-    // Scanning for tasks
-
-    /**
-     * Repeatedly scans for and tries to steal and execute (via
-     * workQueue.runTask) a queued task. Each scan traverses queues in
-     * pseudorandom permutation. Upon finding a non-empty queue, makes
-     * at most the given bound attempts to re-poll (fewer if
-     * contended) on the same queue before returning (impossible
-     * scanState value) 0 to restart scan. Else returns after at least
-     * 1 and at most 32 full scans.
-     *
-     * @param w the worker (via its WorkQueue)
-     * @param bound repoll bound as bitmask (0 if spare)
-     * @param step (circular) index increment per iteration (must be odd)
-     * @param r a random seed for origin index
-     * @return negative if should await signal
-     */
-    private int scan(WorkQueue w, int bound, int step, int r) {
-        int stat = 0, wl; WorkQueue[] ws;
-        if ((ws = workQueues) != null && w != null && (wl = ws.length) > 0) {
-            for (int m = wl - 1,
-                     origin = m & r, idx = origin,
-                     npolls = 0,
-                     ss = w.scanState;;) {         // negative if inactive
-                WorkQueue q; ForkJoinTask<?>[] a; int b, al;
-                if ((q = ws[idx]) != null && (b = q.base) - q.top < 0 &&
-                    (a = q.array) != null && (al = a.length) > 0) {
-                    int index = (al - 1) & b;
-                    long offset = ((long)index << ASHIFT) + ABASE;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        U.getObjectVolatile(a, offset);
-                    if (t == null)
-                        break;                     // empty or busy
-                    else if (b++ != q.base)
-                        break;                     // busy
-                    else if (ss < 0) {
-                        tryReactivate(w, ws, r);
-                        break;                     // retry upon rescan
-                    }
-                    else if (!U.compareAndSwapObject(a, offset, t, null))
-                        break;                     // contended
-                    else {
-                        q.base = b;
-                        w.currentSteal = t;
-                        if (b != q.top)            // propagate signal
-                            signalWork();
-                        w.runTask(t);
-                        if (++npolls > bound)
-                            break;
-                    }
-                }
-                else if (npolls != 0)              // rescan
+            else if ((phase = w.phase) >= 0) {    // enqueue, then rescan
+                long np = (w.phase = (phase + SS_SEQ) | UNSIGNALLED) & SP_MASK;
+                long c, nc;
+                do {
+                    w.stackPred = (int)(c = ctl);
+                    nc = ((c - RC_UNIT) & UC_MASK) | np;
+                } while (!CTL.weakCompareAndSet(this, c, nc));
+            }
+            else {                                // already queued
+                int pred = w.stackPred;
+                Thread.interrupted();             // clear before park
+                w.source = DORMANT;               // enable signal
+                long c = ctl;
+                int md = mode, rc = (md & SMASK) + (int)(c >> RC_SHIFT);
+                if (md < 0)                       // terminating
                     break;
-                else if ((idx = (idx + step) & m) == origin) {
-                    if (ss < 0) {                  // await signal
-                        stat = ss;
+                else if (rc <= 0 && (md & SHUTDOWN) != 0 &&
+                         tryTerminate(false, false))
+                    break;                        // quiescent shutdown
+                else if (rc <= 0 && pred != 0 && phase == (int)c) {
+                    long nc = (UC_MASK & (c - TC_UNIT)) | (SP_MASK & pred);
+                    long d = keepAlive + System.currentTimeMillis();
+                    LockSupport.parkUntil(this, d);
+                    if (ctl == c &&               // drop on timeout if all idle
+                        d - System.currentTimeMillis() <= TIMEOUT_SLOP &&
+                        CTL.compareAndSet(this, c, nc)) {
+                        w.phase = QUIET;
                         break;
                     }
-                    else if (r >= 0) {
-                        inactivate(w, ss);
-                        break;
-                    }
-                    else
-                        r <<= 1;                   // at most 31 rescans
                 }
+                else if (w.phase < 0)
+                    LockSupport.park(this);       // OK if spuriously woken
+                w.source = 0;                     // disable signal
             }
         }
-        return stat;
     }
 
-    // Joining tasks
-
     /**
-     * Tries to steal and run tasks within the target's computation.
-     * Uses a variant of the top-level algorithm, restricted to tasks
-     * with the given task as ancestor: It prefers taking and running
-     * eligible tasks popped from the worker's own queue (via
-     * popCC). Otherwise it scans others, randomly moving on
-     * contention or execution, deciding to give up based on a
-     * checksum (via return codes from pollAndExecCC). The maxTasks
-     * argument supports external usages; internal calls use zero,
-     * allowing unbounded steps (external calls trap non-positive
-     * values).
+     * Scans for and if found executes one or more top-level tasks from a queue.
      *
-     * @param w caller
-     * @param maxTasks if non-zero, the maximum number of other tasks to run
-     * @return task status on exit
+     * @return true if found an apparently non-empty queue, and
+     * possibly ran task(s).
      */
-    final int helpComplete(WorkQueue w, CountedCompleter<?> task,
-                           int maxTasks) {
-        WorkQueue[] ws; int s = 0, wl;
-        if ((ws = workQueues) != null && (wl = ws.length) > 1 &&
-            task != null && w != null) {
-            for (int m = wl - 1,
-                     mode = w.config,
-                     r = ~mode,                  // scanning seed
-                     origin = r & m, k = origin, // first queue to scan
-                     step = 3,                   // first scan step
-                     h = 1,                      // 1:ran, >1:contended, <0:hash
-                     oldSum = 0, checkSum = 0;;) {
-                CountedCompleter<?> p; WorkQueue q; int i;
-                if ((s = task.status) < 0)
+    private boolean scan(WorkQueue w, int r) {
+        WorkQueue[] ws; int n;
+        if ((ws = workQueues) != null && (n = ws.length) > 0 && w != null) {
+            for (int m = n - 1, j = r & m;;) {
+                WorkQueue q; int b;
+                if ((q = ws[j]) != null && q.top != (b = q.base)) {
+                    int qid = q.id;
+                    ForkJoinTask<?>[] a; int cap, k; ForkJoinTask<?> t;
+                    if ((a = q.array) != null && (cap = a.length) > 0) {
+                        t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
+                        if (q.base == b++ && t != null &&
+                            QA.compareAndSet(a, k, t, null)) {
+                            q.base = b;
+                            w.source = qid;
+                            if (q.top - b > 0)
+                                signalWork();
+                            w.topLevelExec(t, q,  // random fairness bound
+                                           r & ((n << TOP_BOUND_SHIFT) - 1));
+                        }
+                    }
+                    return true;
+                }
+                else if (--n > 0)
+                    j = (j + 1) & m;
+                else
                     break;
-                if (h == 1 && (p = w.popCC(task, mode)) != null) {
-                    p.doExec();                  // run local task
-                    if (maxTasks != 0 && --maxTasks == 0)
-                        break;
-                    origin = k;                  // reset
-                    oldSum = checkSum = 0;
-                }
-                else {                           // poll other worker queues
-                    if ((i = k | 1) < 0 || i > m || (q = ws[i]) == null)
-                        h = 0;
-                    else if ((h = q.pollAndExecCC(task)) < 0)
-                        checkSum += h;
-                    if (h > 0) {
-                        if (h == 1 && maxTasks != 0 && --maxTasks == 0)
-                            break;
-                        step = (r >>> 16) | 3;
-                        r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
-                        k = origin = r & m;      // move and restart
-                        oldSum = checkSum = 0;
-                    }
-                    else if ((k = (k + step) & m) == origin) {
-                        if (oldSum == (oldSum = checkSum))
-                            break;
-                        checkSum = 0;
-                    }
-                }
             }
         }
-        return s;
-    }
-
-    /**
-     * Tries to locate and execute tasks for a stealer of the given
-     * task, or in turn one of its stealers. Traces currentSteal ->
-     * currentJoin links looking for a thread working on a descendant
-     * of the given task and with a non-empty queue to steal back and
-     * execute tasks from. The first call to this method upon a
-     * waiting join will often entail scanning/search, (which is OK
-     * because the joiner has nothing better to do), but this method
-     * leaves hints in workers to speed up subsequent calls.
-     *
-     * @param w caller
-     * @param task the task to join
-     */
-    private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
-        if (task != null && w != null) {
-            ForkJoinTask<?> ps = w.currentSteal;
-            WorkQueue[] ws; int wl, oldSum = 0;
-            outer: while (w.tryRemoveAndExec(task) && task.status >= 0 &&
-                          (ws = workQueues) != null && (wl = ws.length) > 0) {
-                ForkJoinTask<?> subtask;
-                int m = wl - 1, checkSum = 0;          // for stability check
-                WorkQueue j = w, v;                    // v is subtask stealer
-                descent: for (subtask = task; subtask.status >= 0; ) {
-                    for (int h = j.hint | 1, k = 0, i;;) {
-                        if ((v = ws[i = (h + (k << 1)) & m]) != null) {
-                            if (v.currentSteal == subtask) {
-                                j.hint = i;
-                                break;
-                            }
-                            checkSum += v.base;
-                        }
-                        if (++k > m)                   // can't find stealer
-                            break outer;
-                    }
-
-                    for (;;) {                         // help v or descend
-                        ForkJoinTask<?>[] a; int b, al;
-                        if (subtask.status < 0)        // too late to help
-                            break descent;
-                        checkSum += (b = v.base);
-                        ForkJoinTask<?> next = v.currentJoin;
-                        ForkJoinTask<?> t = null;
-                        if ((a = v.array) != null && (al = a.length) > 0) {
-                            int index = (al - 1) & b;
-                            long offset = ((long)index << ASHIFT) + ABASE;
-                            t = (ForkJoinTask<?>)
-                                U.getObjectVolatile(a, offset);
-                            if (t != null && b++ == v.base) {
-                                if (j.currentJoin != subtask ||
-                                    v.currentSteal != subtask ||
-                                    subtask.status < 0)
-                                    break descent;     // stale
-                                if (U.compareAndSwapObject(a, offset, t, null)) {
-                                    v.base = b;
-                                    w.currentSteal = t;
-                                    for (int top = w.top;;) {
-                                        t.doExec();    // help
-                                        w.currentSteal = ps;
-                                        if (task.status < 0)
-                                            break outer;
-                                        if (w.top == top)
-                                            break;     // run local tasks
-                                        if ((t = w.pop()) == null)
-                                            break descent;
-                                        w.currentSteal = t;
-                                    }
-                                }
-                            }
-                        }
-                        if (t == null && b == v.base && b - v.top >= 0) {
-                            if ((subtask = next) == null) {  // try to descend
-                                if (next == v.currentJoin &&
-                                    oldSum == (oldSum = checkSum))
-                                    break outer;
-                                break descent;
-                            }
-                            j = v;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Tries to decrement active count (sometimes implicitly) and
-     * possibly release or create a compensating worker in preparation
-     * for blocking. Returns false (retryable by caller), on
-     * contention, detected staleness, instability, or termination.
-     *
-     * @param w caller
-     */
-    private boolean tryCompensate(WorkQueue w) {
-        boolean canBlock; int wl;
-        long c = ctl;
-        WorkQueue[] ws = workQueues;
-        int pc = config & SMASK;
-        int ac = pc + (int)(c >> AC_SHIFT);
-        int tc = pc + (short)(c >> TC_SHIFT);
-        if (w == null || w.qlock < 0 || pc == 0 ||  // terminating or disabled
-            ws == null || (wl = ws.length) <= 0)
-            canBlock = false;
-        else {
-            int m = wl - 1, sp;
-            boolean busy = true;                    // validate ac
-            for (int i = 0; i <= m; ++i) {
-                int k; WorkQueue v;
-                if ((k = (i << 1) | 1) <= m && k >= 0 && (v = ws[k]) != null &&
-                    v.scanState >= 0 && v.currentSteal == null) {
-                    busy = false;
-                    break;
-                }
-            }
-            if (!busy || ctl != c)
-                canBlock = false;                   // unstable or stale
-            else if ((sp = (int)c) != 0)            // release idle worker
-                canBlock = tryRelease(c, ws[m & sp], 0L);
-            else if (tc >= pc && ac > 1 && w.isEmpty()) {
-                long nc = ((AC_MASK & (c - AC_UNIT)) |
-                           (~AC_MASK & c));         // uncompensated
-                canBlock = U.compareAndSwapLong(this, CTL, c, nc);
-            }
-            else if (tc >= MAX_CAP ||
-                     (this == common && tc >= pc + COMMON_MAX_SPARES))
-                throw new RejectedExecutionException(
-                    "Thread limit exceeded replacing blocked worker");
-            else {                                  // similar to tryAddWorker
-                boolean isSpare = (tc >= pc);
-                long nc = (AC_MASK & c) | (TC_MASK & (c + TC_UNIT));
-                canBlock = (U.compareAndSwapLong(this, CTL, c, nc) &&
-                            createWorker(isSpare)); // throws on exception
-            }
-        }
-        return canBlock;
+        return false;
     }
 
     /**
      * Helps and/or blocks until the given task is done or timeout.
+     * First tries locally helping, then scans other queues for a task
+     * produced by one of w's stealers; compensating and blocking if
+     * none are found (rescanning if tryCompensate fails).
      *
      * @param w caller
      * @param task the task
@@ -2225,62 +1682,165 @@
      */
     final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
         int s = 0;
-        if (w != null) {
-            ForkJoinTask<?> prevJoin = w.currentJoin;
-            if (task != null && (s = task.status) >= 0) {
-                w.currentJoin = task;
-                CountedCompleter<?> cc = (task instanceof CountedCompleter) ?
-                    (CountedCompleter<?>)task : null;
-                for (;;) {
-                    if (cc != null)
-                        helpComplete(w, cc, 0);
-                    else
-                        helpStealer(w, task);
-                    if ((s = task.status) < 0)
+        int seed = ThreadLocalRandom.nextSecondarySeed();
+        if (w != null && task != null &&
+            (!(task instanceof CountedCompleter) ||
+             (s = w.helpCC((CountedCompleter<?>)task, 0, false)) >= 0)) {
+            w.tryRemoveAndExec(task);
+            int src = w.source, id = w.id;
+            int r = (seed >>> 16) | 1, step = (seed & ~1) | 2;
+            s = task.status;
+            while (s >= 0) {
+                WorkQueue[] ws;
+                int n = (ws = workQueues) == null ? 0 : ws.length, m = n - 1;
+                while (n > 0) {
+                    WorkQueue q; int b;
+                    if ((q = ws[r & m]) != null && q.source == id &&
+                        q.top != (b = q.base)) {
+                        ForkJoinTask<?>[] a; int cap, k;
+                        int qid = q.id;
+                        if ((a = q.array) != null && (cap = a.length) > 0) {
+                            ForkJoinTask<?> t = (ForkJoinTask<?>)
+                                QA.getAcquire(a, k = (cap - 1) & b);
+                            if (q.source == id && q.base == b++ &&
+                                t != null && QA.compareAndSet(a, k, t, null)) {
+                                q.base = b;
+                                w.source = qid;
+                                t.doExec();
+                                w.source = src;
+                            }
+                        }
                         break;
-                    long ms, ns;
-                    if (deadline == 0L)
-                        ms = 0L;
-                    else if ((ns = deadline - System.nanoTime()) <= 0L)
-                        break;
-                    else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
-                        ms = 1L;
-                    if (tryCompensate(w)) {
-                        task.internalWait(ms);
-                        U.getAndAddLong(this, CTL, AC_UNIT);
                     }
-                    if ((s = task.status) < 0)
-                        break;
+                    else {
+                        r += step;
+                        --n;
+                    }
                 }
-                w.currentJoin = prevJoin;
+                if ((s = task.status) < 0)
+                    break;
+                else if (n == 0) { // empty scan
+                    long ms, ns; int block;
+                    if (deadline == 0L)
+                        ms = 0L;                       // untimed
+                    else if ((ns = deadline - System.nanoTime()) <= 0L)
+                        break;                         // timeout
+                    else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
+                        ms = 1L;                       // avoid 0 for timed wait
+                    if ((block = tryCompensate(w)) != 0) {
+                        task.internalWait(ms);
+                        CTL.getAndAdd(this, (block > 0) ? RC_UNIT : 0L);
+                    }
+                    s = task.status;
+                }
             }
         }
         return s;
     }
 
-    // Specialized scanning
+    /**
+     * Runs tasks until {@code isQuiescent()}. Rather than blocking
+     * when tasks cannot be found, rescans until all others cannot
+     * find tasks either.
+     */
+    final void helpQuiescePool(WorkQueue w) {
+        int prevSrc = w.source;
+        int seed = ThreadLocalRandom.nextSecondarySeed();
+        int r = seed >>> 16, step = r | 1;
+        for (int source = prevSrc, released = -1;;) { // -1 until known
+            ForkJoinTask<?> localTask; WorkQueue[] ws;
+            while ((localTask = w.nextLocalTask()) != null)
+                localTask.doExec();
+            if (w.phase >= 0 && released == -1)
+                released = 1;
+            boolean quiet = true, empty = true;
+            int n = (ws = workQueues) == null ? 0 : ws.length;
+            for (int m = n - 1; n > 0; r += step, --n) {
+                WorkQueue q; int b;
+                if ((q = ws[r & m]) != null) {
+                    int qs = q.source;
+                    if (q.top != (b = q.base)) {
+                        quiet = empty = false;
+                        ForkJoinTask<?>[] a; int cap, k;
+                        int qid = q.id;
+                        if ((a = q.array) != null && (cap = a.length) > 0) {
+                            if (released == 0) {    // increment
+                                released = 1;
+                                CTL.getAndAdd(this, RC_UNIT);
+                            }
+                            ForkJoinTask<?> t = (ForkJoinTask<?>)
+                                QA.getAcquire(a, k = (cap - 1) & b);
+                            if (q.base == b++ && t != null &&
+                                QA.compareAndSet(a, k, t, null)) {
+                                q.base = b;
+                                w.source = qid;
+                                t.doExec();
+                                w.source = source = prevSrc;
+                            }
+                        }
+                        break;
+                    }
+                    else if ((qs & QUIET) == 0)
+                        quiet = false;
+                }
+            }
+            if (quiet) {
+                if (released == 0)
+                    CTL.getAndAdd(this, RC_UNIT);
+                w.source = prevSrc;
+                break;
+            }
+            else if (empty) {
+                if (source != QUIET)
+                    w.source = source = QUIET;
+                if (released == 1) {                 // decrement
+                    released = 0;
+                    CTL.getAndAdd(this, RC_MASK & -RC_UNIT);
+                }
+            }
+        }
+    }
 
     /**
-     * Returns a (probably) non-empty steal queue, if one is found
-     * during a scan, else null.  This method must be retried by
-     * caller if, by the time it tries to use the queue, it is empty.
+     * Scans for and returns a polled task, if available.
+     * Used only for untracked polls.
+     *
+     * @param submissionsOnly if true, only scan submission queues
      */
-    private WorkQueue findNonEmptyStealQueue() {
-        WorkQueue[] ws; int wl;  // one-shot version of scan loop
-        int r = ThreadLocalRandom.nextSecondarySeed();
-        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
-            int m = wl - 1, origin = r & m;
-            for (int k = origin, oldSum = 0, checkSum = 0;;) {
-                WorkQueue q; int b;
-                if ((q = ws[k]) != null) {
-                    if ((b = q.base) - q.top < 0)
-                        return q;
-                    checkSum += b;
+    private ForkJoinTask<?> pollScan(boolean submissionsOnly) {
+        WorkQueue[] ws; int n;
+        rescan: while ((mode & STOP) == 0 && (ws = workQueues) != null &&
+                      (n = ws.length) > 0) {
+            int m = n - 1;
+            int r = ThreadLocalRandom.nextSecondarySeed();
+            int h = r >>> 16;
+            int origin, step;
+            if (submissionsOnly) {
+                origin = (r & ~1) & m;         // even indices and steps
+                step = (h & ~1) | 2;
+            }
+            else {
+                origin = r & m;
+                step = h | 1;
+            }
+            boolean nonempty = false;
+            for (int i = origin, oldSum = 0, checkSum = 0;;) {
+                WorkQueue q;
+                if ((q = ws[i]) != null) {
+                    int b; ForkJoinTask<?> t;
+                    if (q.top - (b = q.base) > 0) {
+                        nonempty = true;
+                        if ((t = q.poll()) != null)
+                            return t;
+                    }
+                    else
+                        checkSum += b + q.id;
                 }
-                if ((k = (k + 1) & m) == origin) {
-                    if (oldSum == (oldSum = checkSum))
-                        break;
+                if ((i = (i + step) & m) == origin) {
+                    if (!nonempty && oldSum == (oldSum = checkSum))
+                        break rescan;
                     checkSum = 0;
+                    nonempty = false;
                 }
             }
         }
@@ -2288,58 +1848,129 @@
     }
 
     /**
-     * Runs tasks until {@code isQuiescent()}. We piggyback on
-     * active count ctl maintenance, but rather than blocking
-     * when tasks cannot be found, we rescan until all others cannot
-     * find tasks either.
-     */
-    final void helpQuiescePool(WorkQueue w) {
-        ForkJoinTask<?> ps = w.currentSteal; // save context
-        int wc = w.config;
-        for (boolean active = true;;) {
-            long c; WorkQueue q; ForkJoinTask<?> t;
-            if (wc >= 0 && (t = w.pop()) != null) { // run locals if LIFO
-                (w.currentSteal = t).doExec();
-                w.currentSteal = ps;
-            }
-            else if ((q = findNonEmptyStealQueue()) != null) {
-                if (!active) {      // re-establish active count
-                    active = true;
-                    U.getAndAddLong(this, CTL, AC_UNIT);
-                }
-                if ((t = q.pollAt(q.base)) != null) {
-                    (w.currentSteal = t).doExec();
-                    w.currentSteal = ps;
-                    if (++w.nsteals < 0)
-                        w.transferStealCount(this);
-                }
-            }
-            else if (active) {      // decrement active count without queuing
-                long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c);
-                if (U.compareAndSwapLong(this, CTL, c, nc))
-                    active = false;
-            }
-            else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 &&
-                     U.compareAndSwapLong(this, CTL, c, c + AC_UNIT))
-                break;
-        }
-    }
-
-    /**
      * Gets and removes a local or stolen task for the given worker.
      *
      * @return a task, if available
      */
     final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
-        for (ForkJoinTask<?> t;;) {
-            WorkQueue q;
-            if ((t = w.nextLocalTask()) != null)
-                return t;
-            if ((q = findNonEmptyStealQueue()) == null)
-                return null;
-            if ((t = q.pollAt(q.base)) != null)
-                return t;
+        ForkJoinTask<?> t;
+        if (w == null || (t = w.nextLocalTask()) == null)
+            t = pollScan(false);
+        return t;
+    }
+
+    // External operations
+
+    /**
+     * Adds the given task to a submission queue at submitter's
+     * current queue, creating one if null or contended.
+     *
+     * @param task the task. Caller must ensure non-null.
+     */
+    final void externalPush(ForkJoinTask<?> task) {
+        int r;                                // initialize caller's probe
+        if ((r = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();
+            r = ThreadLocalRandom.getProbe();
         }
+        for (;;) {
+            WorkQueue q;
+            int md = mode, n;
+            WorkQueue[] ws = workQueues;
+            if ((md & SHUTDOWN) != 0 || ws == null || (n = ws.length) <= 0)
+                throw new RejectedExecutionException();
+            else if ((q = ws[(n - 1) & r & SQMASK]) == null) { // add queue
+                int qid = (r | QUIET) & ~(FIFO | OWNED);
+                Object lock = workerNamePrefix;
+                ForkJoinTask<?>[] qa =
+                    new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
+                q = new WorkQueue(this, null);
+                q.array = qa;
+                q.id = qid;
+                q.source = QUIET;
+                if (lock != null) {     // unless disabled, lock pool to install
+                    synchronized (lock) {
+                        WorkQueue[] vs; int i, vn;
+                        if ((vs = workQueues) != null && (vn = vs.length) > 0 &&
+                            vs[i = qid & (vn - 1) & SQMASK] == null)
+                            vs[i] = q;  // else another thread already installed
+                    }
+                }
+            }
+            else if (!q.tryLockPhase()) // move if busy
+                r = ThreadLocalRandom.advanceProbe(r);
+            else {
+                if (q.lockedPush(task))
+                    signalWork();
+                return;
+            }
+        }
+    }
+
+    /**
+     * Pushes a possibly-external submission.
+     */
+    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
+        Thread t; ForkJoinWorkerThread w; WorkQueue q;
+        if (task == null)
+            throw new NullPointerException();
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (w = (ForkJoinWorkerThread)t).pool == this &&
+            (q = w.workQueue) != null)
+            q.push(task);
+        else
+            externalPush(task);
+        return task;
+    }
+
+    /**
+     * Returns common pool queue for an external thread.
+     */
+    static WorkQueue commonSubmitterQueue() {
+        ForkJoinPool p = common;
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; int n;
+        return (p != null && (ws = p.workQueues) != null &&
+                (n = ws.length) > 0) ?
+            ws[(n - 1) & r & SQMASK] : null;
+    }
+
+    /**
+     * Performs tryUnpush for an external submitter.
+     */
+    final boolean tryExternalUnpush(ForkJoinTask<?> task) {
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; WorkQueue w; int n;
+        return ((ws = workQueues) != null &&
+                (n = ws.length) > 0 &&
+                (w = ws[(n - 1) & r & SQMASK]) != null &&
+                w.tryLockedUnpush(task));
+    }
+
+    /**
+     * Performs helpComplete for an external submitter.
+     */
+    final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; WorkQueue w; int n;
+        return ((ws = workQueues) != null && (n = ws.length) > 0 &&
+                (w = ws[(n - 1) & r & SQMASK]) != null) ?
+            w.helpCC(task, maxTasks, true) : 0;
+    }
+
+    /**
+     * Tries to steal and run tasks within the target's computation.
+     * The maxTasks argument supports external usages; internal calls
+     * use zero, allowing unbounded steps (external calls trap
+     * non-positive values).
+     *
+     * @param w caller
+     * @param maxTasks if non-zero, the maximum number of other tasks to run
+     * @return task status on exit
+     */
+    final int helpComplete(WorkQueue w, CountedCompleter<?> task,
+                           int maxTasks) {
+        return (w == null) ? 0 : w.helpCC(task, maxTasks, false);
     }
 
     /**
@@ -2386,10 +2017,12 @@
      */
     static int getSurplusQueuedTaskCount() {
         Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
-        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
-            int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK;
-            int n = (q = wt.workQueue).top - q.base;
-            int a = (int)(pool.ctl >> AC_SHIFT) + p;
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (pool = (wt = (ForkJoinWorkerThread)t).pool) != null &&
+            (q = wt.workQueue) != null) {
+            int p = pool.mode & SMASK;
+            int a = p + (int)(pool.ctl >> RC_SHIFT);
+            int n = q.top - q.base;
             return n - (a > (p >>>= 1) ? 0 :
                         a > (p >>>= 1) ? 1 :
                         a > (p >>>= 1) ? 2 :
@@ -2399,7 +2032,7 @@
         return 0;
     }
 
-    //  Termination
+    // Termination
 
     /**
      * Possibly initiates and/or completes termination.
@@ -2407,198 +2040,89 @@
      * @param now if true, unconditionally terminate, else only
      * if no work and no active workers
      * @param enable if true, terminate when next possible
-     * @return -1: terminating/terminated, 0: retry if internal caller, else 1
+     * @return true if terminating or terminated
      */
-    private int tryTerminate(boolean now, boolean enable) {
-        int rs; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
+    private boolean tryTerminate(boolean now, boolean enable) {
+        int md; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
 
-        while ((rs = runState) >= 0) {
+        while (((md = mode) & SHUTDOWN) == 0) {
             if (!enable || this == common)        // cannot shutdown
-                return 1;
-            else if (rs == 0)
-                tryInitialize(false);             // ensure initialized
+                return false;
             else
-                U.compareAndSwapInt(this, RUNSTATE, rs, rs | SHUTDOWN);
+                MODE.compareAndSet(this, md, md | SHUTDOWN);
         }
 
-        if ((rs & STOP) == 0) {                   // try to initiate termination
-            if (!now) {                           // check quiescence
+        while (((md = mode) & STOP) == 0) {       // try to initiate termination
+            if (!now) {                           // check if quiescent & empty
                 for (long oldSum = 0L;;) {        // repeat until stable
-                    WorkQueue[] ws; WorkQueue w; int b;
+                    boolean running = false;
                     long checkSum = ctl;
-                    if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
-                        return 0;                 // still active workers
-                    if ((ws = workQueues) != null) {
+                    WorkQueue[] ws = workQueues;
+                    if ((md & SMASK) + (int)(checkSum >> RC_SHIFT) > 0)
+                        running = true;
+                    else if (ws != null) {
+                        WorkQueue w;
                         for (int i = 0; i < ws.length; ++i) {
                             if ((w = ws[i]) != null) {
-                                checkSum += (b = w.base);
-                                if (w.currentSteal != null || b != w.top)
-                                    return 0;     // retry if internal caller
+                                int s = w.source, p = w.phase;
+                                int d = w.id, b = w.base;
+                                if (b != w.top ||
+                                    ((d & 1) == 1 && (s >= 0 || p >= 0))) {
+                                    running = true;
+                                    break;     // working, scanning, or have work
+                                }
+                                checkSum += (((long)s << 48) + ((long)p << 32) +
+                                             ((long)b << 16) + (long)d);
                             }
                         }
                     }
-                    if (oldSum == (oldSum = checkSum))
+                    if (((md = mode) & STOP) != 0)
+                        break;                 // already triggered
+                    else if (running)
+                        return false;
+                    else if (workQueues == ws && oldSum == (oldSum = checkSum))
                         break;
                 }
             }
-            do {} while (!U.compareAndSwapInt(this, RUNSTATE,
-                                              rs = runState, rs | STOP));
+            if ((md & STOP) == 0)
+                MODE.compareAndSet(this, md, md | STOP);
         }
 
-        for (long oldSum = 0L;;) {                // repeat until stable
-            WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt;
-            long checkSum = ctl;
-            if ((ws = workQueues) != null) {      // help terminate others
-                for (int i = 0; i < ws.length; ++i) {
-                    if ((w = ws[i]) != null) {
-                        w.cancelAll();            // clear queues
-                        checkSum += w.base;
-                        if (w.qlock >= 0) {
-                            w.qlock = -1;         // racy set OK
-                            if ((wt = w.owner) != null) {
+        while (((md = mode) & TERMINATED) == 0) { // help terminate others
+            for (long oldSum = 0L;;) {            // repeat until stable
+                WorkQueue[] ws; WorkQueue w;
+                long checkSum = ctl;
+                if ((ws = workQueues) != null) {
+                    for (int i = 0; i < ws.length; ++i) {
+                        if ((w = ws[i]) != null) {
+                            ForkJoinWorkerThread wt = w.owner;
+                            w.cancelAll();        // clear queues
+                            if (wt != null) {
                                 try {             // unblock join or park
                                     wt.interrupt();
                                 } catch (Throwable ignore) {
                                 }
                             }
+                            checkSum += ((long)w.phase << 32) + w.base;
                         }
                     }
                 }
+                if (((md = mode) & TERMINATED) != 0 ||
+                    (workQueues == ws && oldSum == (oldSum = checkSum)))
+                    break;
             }
-            if (oldSum == (oldSum = checkSum))
+            if ((md & TERMINATED) != 0)
                 break;
-        }
-
-        if ((short)(ctl >>> TC_SHIFT) + (config & SMASK) <= 0) {
-            runState = (STARTED | SHUTDOWN | STOP | TERMINATED); // final write
-            synchronized (this) {
-                notifyAll();                      // for awaitTermination
-            }
-        }
-
-        return -1;
-    }
-
-    // External operations
-
-    /**
-     * Constructs and tries to install a new external queue,
-     * failing if the workQueues array already has a queue at
-     * the given index.
-     *
-     * @param index the index of the new queue
-     */
-    private void tryCreateExternalQueue(int index) {
-        AuxState aux;
-        if ((aux = auxState) != null && index >= 0) {
-            WorkQueue q = new WorkQueue(this, null);
-            q.config = index;
-            q.scanState = ~UNSIGNALLED;
-            q.qlock = 1;                   // lock queue
-            boolean installed = false;
-            aux.lock();
-            try {                          // lock pool to install
-                WorkQueue[] ws;
-                if ((ws = workQueues) != null && index < ws.length &&
-                    ws[index] == null) {
-                    ws[index] = q;         // else throw away
-                    installed = true;
+            else if ((md & SMASK) + (short)(ctl >>> TC_SHIFT) > 0)
+                break;
+            else if (MODE.compareAndSet(this, md, md | TERMINATED)) {
+                synchronized (this) {
+                    notifyAll();                  // for awaitTermination
                 }
-            } finally {
-                aux.unlock();
-            }
-            if (installed) {
-                try {
-                    q.growArray();
-                } finally {
-                    q.qlock = 0;
-                }
-            }
-        }
-    }
-
-    /**
-     * Adds the given task to a submission queue at submitter's
-     * current queue. Also performs secondary initialization upon the
-     * first submission of the first task to the pool, and detects
-     * first submission by an external thread and creates a new shared
-     * queue if the one at index if empty or contended.
-     *
-     * @param task the task. Caller must ensure non-null.
-     */
-    final void externalPush(ForkJoinTask<?> task) {
-        int r;                            // initialize caller's probe
-        if ((r = ThreadLocalRandom.getProbe()) == 0) {
-            ThreadLocalRandom.localInit();
-            r = ThreadLocalRandom.getProbe();
-        }
-        for (;;) {
-            WorkQueue q; int wl, k, stat;
-            int rs = runState;
-            WorkQueue[] ws = workQueues;
-            if (rs <= 0 || ws == null || (wl = ws.length) <= 0)
-                tryInitialize(true);
-            else if ((q = ws[k = (wl - 1) & r & SQMASK]) == null)
-                tryCreateExternalQueue(k);
-            else if ((stat = q.sharedPush(task)) < 0)
-                break;
-            else if (stat == 0) {
-                signalWork();
                 break;
             }
-            else                          // move if busy
-                r = ThreadLocalRandom.advanceProbe(r);
         }
-    }
-
-    /**
-     * Pushes a possibly-external submission.
-     */
-    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
-        Thread t; ForkJoinWorkerThread w; WorkQueue q;
-        if (task == null)
-            throw new NullPointerException();
-        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
-            (w = (ForkJoinWorkerThread)t).pool == this &&
-            (q = w.workQueue) != null)
-            q.push(task);
-        else
-            externalPush(task);
-        return task;
-    }
-
-    /**
-     * Returns common pool queue for an external thread.
-     */
-    static WorkQueue commonSubmitterQueue() {
-        ForkJoinPool p = common;
-        int r = ThreadLocalRandom.getProbe();
-        WorkQueue[] ws; int wl;
-        return (p != null && (ws = p.workQueues) != null &&
-                (wl = ws.length) > 0) ?
-            ws[(wl - 1) & r & SQMASK] : null;
-    }
-
-    /**
-     * Performs tryUnpush for an external submitter.
-     */
-    final boolean tryExternalUnpush(ForkJoinTask<?> task) {
-        int r = ThreadLocalRandom.getProbe();
-        WorkQueue[] ws; WorkQueue w; int wl;
-        return ((ws = workQueues) != null &&
-                (wl = ws.length) > 0 &&
-                (w = ws[(wl - 1) & r & SQMASK]) != null &&
-                w.trySharedUnpush(task));
-    }
-
-    /**
-     * Performs helpComplete for an external submitter.
-     */
-    final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
-        WorkQueue[] ws; int wl;
-        int r = ThreadLocalRandom.getProbe();
-        return ((ws = workQueues) != null && (wl = ws.length) > 0) ?
-            helpComplete(ws[(wl - 1) & r & SQMASK], task, maxTasks) : 0;
+        return true;
     }
 
     // Exported methods
@@ -2607,9 +2131,10 @@
 
     /**
      * Creates a {@code ForkJoinPool} with parallelism equal to {@link
-     * java.lang.Runtime#availableProcessors}, using the {@linkplain
-     * #defaultForkJoinWorkerThreadFactory default thread factory},
-     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     * java.lang.Runtime#availableProcessors}, using defaults for all
+     * other parameters (see {@link #ForkJoinPool(int,
+     * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
+     * int, int, int, Predicate, long, TimeUnit)}).
      *
      * @throws SecurityException if a security manager exists and
      *         the caller is not permitted to modify threads
@@ -2618,14 +2143,16 @@
      */
     public ForkJoinPool() {
         this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
-             defaultForkJoinWorkerThreadFactory, null, false);
+             defaultForkJoinWorkerThreadFactory, null, false,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
     }
 
     /**
      * Creates a {@code ForkJoinPool} with the indicated parallelism
-     * level, the {@linkplain
-     * #defaultForkJoinWorkerThreadFactory default thread factory},
-     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     * level, using defaults for all other parameters (see {@link
+     * #ForkJoinPool(int, ForkJoinWorkerThreadFactory,
+     * UncaughtExceptionHandler, boolean, int, int, int, Predicate,
+     * long, TimeUnit)}).
      *
      * @param parallelism the parallelism level
      * @throws IllegalArgumentException if parallelism less than or
@@ -2636,11 +2163,15 @@
      *         java.lang.RuntimePermission}{@code ("modifyThread")}
      */
     public ForkJoinPool(int parallelism) {
-        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
+        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
     }
 
     /**
-     * Creates a {@code ForkJoinPool} with the given parameters.
+     * Creates a {@code ForkJoinPool} with the given parameters (using
+     * defaults for others -- see {@link #ForkJoinPool(int,
+     * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
+     * int, int, int, Predicate, long, TimeUnit)}).
      *
      * @param parallelism the parallelism level. For default value,
      * use {@link java.lang.Runtime#availableProcessors}.
@@ -2667,43 +2198,186 @@
                         ForkJoinWorkerThreadFactory factory,
                         UncaughtExceptionHandler handler,
                         boolean asyncMode) {
-        this(checkParallelism(parallelism),
-             checkFactory(factory),
-             handler,
-             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
-             "ForkJoinPool-" + nextPoolId() + "-worker-");
-        checkPermission();
-    }
-
-    private static int checkParallelism(int parallelism) {
-        if (parallelism <= 0 || parallelism > MAX_CAP)
-            throw new IllegalArgumentException();
-        return parallelism;
-    }
-
-    private static ForkJoinWorkerThreadFactory checkFactory
-        (ForkJoinWorkerThreadFactory factory) {
-        if (factory == null)
-            throw new NullPointerException();
-        return factory;
+        this(parallelism, factory, handler, asyncMode,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
     }
 
     /**
-     * Creates a {@code ForkJoinPool} with the given parameters, without
-     * any security checks or parameter validation.  Invoked directly by
-     * makeCommonPool.
+     * Creates a {@code ForkJoinPool} with the given parameters.
+     *
+     * @param parallelism the parallelism level. For default value,
+     * use {@link java.lang.Runtime#availableProcessors}.
+     *
+     * @param factory the factory for creating new threads. For
+     * default value, use {@link #defaultForkJoinWorkerThreadFactory}.
+     *
+     * @param handler the handler for internal worker threads that
+     * terminate due to unrecoverable errors encountered while
+     * executing tasks. For default value, use {@code null}.
+     *
+     * @param asyncMode if true, establishes local first-in-first-out
+     * scheduling mode for forked tasks that are never joined. This
+     * mode may be more appropriate than default locally stack-based
+     * mode in applications in which worker threads only process
+     * event-style asynchronous tasks.  For default value, use {@code
+     * false}.
+     *
+     * @param corePoolSize the number of threads to keep in the pool
+     * (unless timed out after an elapsed keep-alive). Normally (and
+     * by default) this is the same value as the parallelism level,
+     * but may be set to a larger value to reduce dynamic overhead if
+     * tasks regularly block. Using a smaller value (for example
+     * {@code 0}) has the same effect as the default.
+     *
+     * @param maximumPoolSize the maximum number of threads allowed.
+     * When the maximum is reached, attempts to replace blocked
+     * threads fail.  (However, because creation and termination of
+     * different threads may overlap, and may be managed by the given
+     * thread factory, this value may be transiently exceeded.)  To
+     * arrange the same value as is used by default for the common
+     * pool, use {@code 256} plus the {@code parallelism} level. (By
+     * default, the common pool allows a maximum of 256 spare
+     * threads.)  Using a value (for example {@code
+     * Integer.MAX_VALUE}) larger than the implementation's total
+     * thread limit has the same effect as using this limit (which is
+     * the default).
+     *
+     * @param minimumRunnable the minimum allowed number of core
+     * threads not blocked by a join or {@link ManagedBlocker}.  To
+     * ensure progress, when too few unblocked threads exist and
+     * unexecuted tasks may exist, new threads are constructed, up to
+     * the given maximumPoolSize.  For the default value, use {@code
+     * 1}, that ensures liveness.  A larger value might improve
+     * throughput in the presence of blocked activities, but might
+     * not, due to increased overhead.  A value of zero may be
+     * acceptable when submitted tasks cannot have dependencies
+     * requiring additional threads.
+     *
+     * @param saturate if non-null, a predicate invoked upon attempts
+     * to create more than the maximum total allowed threads.  By
+     * default, when a thread is about to block on a join or {@link
+     * ManagedBlocker}, but cannot be replaced because the
+     * maximumPoolSize would be exceeded, a {@link
+     * RejectedExecutionException} is thrown.  But if this predicate
+     * returns {@code true}, then no exception is thrown, so the pool
+     * continues to operate with fewer than the target number of
+     * runnable threads, which might not ensure progress.
+     *
+     * @param keepAliveTime the elapsed time since last use before
+     * a thread is terminated (and then later replaced if needed).
+     * For the default value, use {@code 60, TimeUnit.SECONDS}.
+     *
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     *
+     * @throws IllegalArgumentException if parallelism is less than or
+     *         equal to zero, or is greater than implementation limit,
+     *         or if maximumPoolSize is less than parallelism,
+     *         of if the keepAliveTime is less than or equal to zero.
+     * @throws NullPointerException if the factory is null
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     * @since 9
      */
-    private ForkJoinPool(int parallelism,
-                         ForkJoinWorkerThreadFactory factory,
-                         UncaughtExceptionHandler handler,
-                         int mode,
-                         String workerNamePrefix) {
-        this.workerNamePrefix = workerNamePrefix;
+    public ForkJoinPool(int parallelism,
+                        ForkJoinWorkerThreadFactory factory,
+                        UncaughtExceptionHandler handler,
+                        boolean asyncMode,
+                        int corePoolSize,
+                        int maximumPoolSize,
+                        int minimumRunnable,
+                        Predicate<? super ForkJoinPool> saturate,
+                        long keepAliveTime,
+                        TimeUnit unit) {
+        // check, encode, pack parameters
+        if (parallelism <= 0 || parallelism > MAX_CAP ||
+            maximumPoolSize < parallelism || keepAliveTime <= 0L)
+            throw new IllegalArgumentException();
+        if (factory == null)
+            throw new NullPointerException();
+        long ms = Math.max(unit.toMillis(keepAliveTime), TIMEOUT_SLOP);
+
+        int corep = Math.min(Math.max(corePoolSize, parallelism), MAX_CAP);
+        long c = ((((long)(-corep)       << TC_SHIFT) & TC_MASK) |
+                  (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
+        int m = parallelism | (asyncMode ? FIFO : 0);
+        int maxSpares = Math.min(maximumPoolSize, MAX_CAP) - parallelism;
+        int minAvail = Math.min(Math.max(minimumRunnable, 0), MAX_CAP);
+        int b = ((minAvail - parallelism) & SMASK) | (maxSpares << SWIDTH);
+        int n = (parallelism > 1) ? parallelism - 1 : 1; // at least 2 slots
+        n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
+        n = (n + 1) << 1; // power of two, including space for submission queues
+
+        this.workerNamePrefix = "ForkJoinPool-" + nextPoolId() + "-worker-";
+        this.workQueues = new WorkQueue[n];
         this.factory = factory;
         this.ueh = handler;
-        this.config = (parallelism & SMASK) | mode;
-        long np = (long)(-parallelism); // offset ctl counts
-        this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
+        this.saturate = saturate;
+        this.keepAlive = ms;
+        this.bounds = b;
+        this.mode = m;
+        this.ctl = c;
+        checkPermission();
+    }
+
+    private static Object newInstanceFromSystemProperty(String property)
+        throws ReflectiveOperationException {
+        String className = System.getProperty(property);
+        return (className == null)
+            ? null
+            : ClassLoader.getSystemClassLoader().loadClass(className)
+            .getConstructor().newInstance();
+    }
+
+    /**
+     * Constructor for common pool using parameters possibly
+     * overridden by system properties
+     */
+    private ForkJoinPool(byte forCommonPoolOnly) {
+        int parallelism = -1;
+        ForkJoinWorkerThreadFactory fac = null;
+        UncaughtExceptionHandler handler = null;
+        try {  // ignore exceptions in accessing/parsing properties
+            String pp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.parallelism");
+            if (pp != null)
+                parallelism = Integer.parseInt(pp);
+            fac = (ForkJoinWorkerThreadFactory) newInstanceFromSystemProperty(
+                "java.util.concurrent.ForkJoinPool.common.threadFactory");
+            handler = (UncaughtExceptionHandler) newInstanceFromSystemProperty(
+                "java.util.concurrent.ForkJoinPool.common.exceptionHandler");
+        } catch (Exception ignore) {
+        }
+
+        if (fac == null) {
+            if (System.getSecurityManager() == null)
+                fac = defaultForkJoinWorkerThreadFactory;
+            else // use security-managed default
+                fac = new InnocuousForkJoinWorkerThreadFactory();
+        }
+        if (parallelism < 0 && // default 1 less than #cores
+            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
+            parallelism = 1;
+        if (parallelism > MAX_CAP)
+            parallelism = MAX_CAP;
+
+        long c = ((((long)(-parallelism) << TC_SHIFT) & TC_MASK) |
+                  (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
+        int b = ((1 - parallelism) & SMASK) | (COMMON_MAX_SPARES << SWIDTH);
+        int n = (parallelism > 1) ? parallelism - 1 : 1;
+        n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
+        n = (n + 1) << 1;
+
+        this.workerNamePrefix = "ForkJoinPool.commonPool-worker-";
+        this.workQueues = new WorkQueue[n];
+        this.factory = fac;
+        this.ueh = handler;
+        this.saturate = null;
+        this.keepAlive = DEFAULT_KEEPALIVE;
+        this.bounds = b;
+        this.mode = parallelism;
+        this.ctl = c;
     }
 
     /**
@@ -2817,15 +2491,13 @@
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
      */
+    @SuppressWarnings("unchecked")
     public ForkJoinTask<?> submit(Runnable task) {
         if (task == null)
             throw new NullPointerException();
-        ForkJoinTask<?> job;
-        if (task instanceof ForkJoinTask<?>) // avoid re-wrap
-            job = (ForkJoinTask<?>) task;
-        else
-            job = new ForkJoinTask.AdaptedRunnableAction(task);
-        return externalSubmit(job);
+        return externalSubmit((task instanceof ForkJoinTask<?>)
+            ? (ForkJoinTask<Void>) task // avoid re-wrap
+            : new ForkJoinTask.AdaptedRunnableAction(task));
     }
 
     /**
@@ -2879,8 +2551,8 @@
      * @return the targeted parallelism level of this pool
      */
     public int getParallelism() {
-        int par;
-        return ((par = config & SMASK) > 0) ? par : 1;
+        int par = mode & SMASK;
+        return (par > 0) ? par : 1;
     }
 
     /**
@@ -2902,7 +2574,7 @@
      * @return the number of worker threads
      */
     public int getPoolSize() {
-        return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
+        return ((mode & SMASK) + (short)(ctl >>> TC_SHIFT));
     }
 
     /**
@@ -2912,7 +2584,7 @@
      * @return {@code true} if this pool uses async mode
      */
     public boolean getAsyncMode() {
-        return (config & FIFO_QUEUE) != 0;
+        return (mode & FIFO) != 0;
     }
 
     /**
@@ -2924,8 +2596,9 @@
      * @return the number of worker threads
      */
     public int getRunningThreadCount() {
-        int rc = 0;
         WorkQueue[] ws; WorkQueue w;
+        VarHandle.acquireFence();
+        int rc = 0;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null && w.isApparentlyUnblocked())
@@ -2943,7 +2616,7 @@
      * @return the number of active threads
      */
     public int getActiveThreadCount() {
-        int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
+        int r = (mode & SMASK) + (int)(ctl >> RC_SHIFT);
         return (r <= 0) ? 0 : r; // suppress momentarily negative values
     }
 
@@ -2959,7 +2632,30 @@
      * @return {@code true} if all threads are currently idle
      */
     public boolean isQuiescent() {
-        return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0;
+        for (;;) {
+            long c = ctl;
+            int md = mode, pc = md & SMASK;
+            int tc = pc + (short)(c >>> TC_SHIFT);
+            int rc = pc + (int)(c >> RC_SHIFT);
+            if ((md & (STOP | TERMINATED)) != 0)
+                return true;
+            else if (rc > 0)
+                return false;
+            else {
+                WorkQueue[] ws; WorkQueue v;
+                if ((ws = workQueues) != null) {
+                    for (int i = 1; i < ws.length; i += 2) {
+                        if ((v = ws[i]) != null) {
+                            if (v.source > 0)
+                                return false;
+                            --tc;
+                        }
+                    }
+                }
+                if (tc == 0 && ctl == c)
+                    return true;
+            }
+        }
     }
 
     /**
@@ -2974,13 +2670,12 @@
      * @return the number of steals
      */
     public long getStealCount() {
-        AuxState sc = auxState;
-        long count = (sc == null) ? 0L : sc.stealCount;
+        long count = stealCount;
         WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
-                    count += w.nsteals;
+                    count += (long)w.nsteals & 0xffffffffL;
             }
         }
         return count;
@@ -2997,8 +2692,9 @@
      * @return the number of queued tasks
      */
     public long getQueuedTaskCount() {
-        long count = 0;
         WorkQueue[] ws; WorkQueue w;
+        VarHandle.acquireFence();
+        int count = 0;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
@@ -3016,8 +2712,9 @@
      * @return the number of queued submissions
      */
     public int getQueuedSubmissionCount() {
-        int count = 0;
         WorkQueue[] ws; WorkQueue w;
+        VarHandle.acquireFence();
+        int count = 0;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
@@ -3035,6 +2732,7 @@
      */
     public boolean hasQueuedSubmissions() {
         WorkQueue[] ws; WorkQueue w;
+        VarHandle.acquireFence();
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null && !w.isEmpty())
@@ -3052,15 +2750,7 @@
      * @return the next submission, or {@code null} if none
      */
     protected ForkJoinTask<?> pollSubmission() {
-        WorkQueue[] ws; int wl; WorkQueue w; ForkJoinTask<?> t;
-        int r = ThreadLocalRandom.nextSecondarySeed();
-        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
-            for (int m = wl - 1, i = 0; i < wl; ++i) {
-                if ((w = ws[(i << 1) & m]) != null && (t = w.poll()) != null)
-                    return t;
-            }
-        }
-        return null;
+        return pollScan(true);
     }
 
     /**
@@ -3081,8 +2771,9 @@
      * @return the number of elements transferred
      */
     protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
-        int count = 0;
         WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+        VarHandle.acquireFence();
+        int count = 0;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; ++i) {
                 if ((w = ws[i]) != null) {
@@ -3105,10 +2796,10 @@
      */
     public String toString() {
         // Use a single pass through workQueues to collect counts
-        long qt = 0L, qs = 0L; int rc = 0;
-        AuxState sc = auxState;
-        long st = (sc == null) ? 0L : sc.stealCount;
+        int md = mode; // read volatile fields first
         long c = ctl;
+        long st = stealCount;
+        long qt = 0L, qs = 0L; int rc = 0;
         WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; ++i) {
@@ -3118,22 +2809,22 @@
                         qs += size;
                     else {
                         qt += size;
-                        st += w.nsteals;
+                        st += (long)w.nsteals & 0xffffffffL;
                         if (w.isApparentlyUnblocked())
                             ++rc;
                     }
                 }
             }
         }
-        int pc = (config & SMASK);
+
+        int pc = (md & SMASK);
         int tc = pc + (short)(c >>> TC_SHIFT);
-        int ac = pc + (int)(c >> AC_SHIFT);
+        int ac = pc + (int)(c >> RC_SHIFT);
         if (ac < 0) // ignore transient negative
             ac = 0;
-        int rs = runState;
-        String level = ((rs & TERMINATED) != 0 ? "Terminated" :
-                        (rs & STOP)       != 0 ? "Terminating" :
-                        (rs & SHUTDOWN)   != 0 ? "Shutting down" :
+        String level = ((md & TERMINATED) != 0 ? "Terminated" :
+                        (md & STOP)       != 0 ? "Terminating" :
+                        (md & SHUTDOWN)   != 0 ? "Shutting down" :
                         "Running");
         return super.toString() +
             "[" + level +
@@ -3196,7 +2887,7 @@
      * @return {@code true} if all tasks have completed following shut down
      */
     public boolean isTerminated() {
-        return (runState & TERMINATED) != 0;
+        return (mode & TERMINATED) != 0;
     }
 
     /**
@@ -3213,8 +2904,8 @@
      * @return {@code true} if terminating but not yet terminated
      */
     public boolean isTerminating() {
-        int rs = runState;
-        return (rs & STOP) != 0 && (rs & TERMINATED) == 0;
+        int md = mode;
+        return (md & STOP) != 0 && (md & TERMINATED) == 0;
     }
 
     /**
@@ -3223,7 +2914,7 @@
      * @return {@code true} if this pool has been shut down
      */
     public boolean isShutdown() {
-        return (runState & SHUTDOWN) != 0;
+        return (mode & SHUTDOWN) != 0;
     }
 
     /**
@@ -3287,30 +2978,19 @@
             helpQuiescePool(wt.workQueue);
             return true;
         }
-        long startTime = System.nanoTime();
-        WorkQueue[] ws;
-        int r = 0, wl;
-        boolean found = true;
-        while (!isQuiescent() && (ws = workQueues) != null &&
-               (wl = ws.length) > 0) {
-            if (!found) {
-                if ((System.nanoTime() - startTime) > nanos)
+        else {
+            for (long startTime = System.nanoTime();;) {
+                ForkJoinTask<?> t;
+                if ((t = pollScan(false)) != null)
+                    t.doExec();
+                else if (isQuiescent())
+                    return true;
+                else if ((System.nanoTime() - startTime) > nanos)
                     return false;
-                Thread.yield(); // cannot block
-            }
-            found = false;
-            for (int m = wl - 1, j = (m + 1) << 2; j >= 0; --j) {
-                ForkJoinTask<?> t; WorkQueue q; int b, k;
-                if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null &&
-                    (b = q.base) - q.top < 0) {
-                    found = true;
-                    if ((t = q.pollAt(b)) != null)
-                        t.doExec();
-                    break;
-                }
+                else
+                    Thread.yield(); // cannot block
             }
         }
-        return true;
     }
 
     /**
@@ -3423,19 +3103,22 @@
      */
     public static void managedBlock(ManagedBlocker blocker)
         throws InterruptedException {
+        if (blocker == null) throw new NullPointerException();
         ForkJoinPool p;
         ForkJoinWorkerThread wt;
+        WorkQueue w;
         Thread t = Thread.currentThread();
         if ((t instanceof ForkJoinWorkerThread) &&
-            (p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
-            WorkQueue w = wt.workQueue;
+            (p = (wt = (ForkJoinWorkerThread)t).pool) != null &&
+            (w = wt.workQueue) != null) {
+            int block;
             while (!blocker.isReleasable()) {
-                if (p.tryCompensate(w)) {
+                if ((block = p.tryCompensate(w)) != 0) {
                     try {
                         do {} while (!blocker.isReleasable() &&
                                      !blocker.block());
                     } finally {
-                        U.getAndAddLong(p, CTL, AC_UNIT);
+                        CTL.getAndAdd(p, (block > 0) ? RC_UNIT : 0L);
                     }
                     break;
                 }
@@ -3447,6 +3130,29 @@
         }
     }
 
+    /**
+     * If the given executor is a ForkJoinPool, poll and execute
+     * AsynchronousCompletionTasks from worker's queue until none are
+     * available or blocker is released.
+     */
+    static void helpAsyncBlocker(Executor e, ManagedBlocker blocker) {
+        if (e instanceof ForkJoinPool) {
+            WorkQueue w; ForkJoinWorkerThread wt; WorkQueue[] ws; int r, n;
+            ForkJoinPool p = (ForkJoinPool)e;
+            Thread thread = Thread.currentThread();
+            if (thread instanceof ForkJoinWorkerThread &&
+                (wt = (ForkJoinWorkerThread)thread).pool == p)
+                w = wt.workQueue;
+            else if ((r = ThreadLocalRandom.getProbe()) != 0 &&
+                     (ws = p.workQueues) != null && (n = ws.length) > 0)
+                w = ws[(n - 1) & r & SQMASK];
+            else
+                w = null;
+            if (w != null)
+                w.helpAsyncBlocker(blocker);
+        }
+    }
+
     // AbstractExecutorService overrides.  These rely on undocumented
     // fact that ForkJoinTask.adapt returns ForkJoinTasks that also
     // implement RunnableFuture.
@@ -3459,26 +3165,19 @@
         return new ForkJoinTask.AdaptedCallable<T>(callable);
     }
 
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long CTL;
-    private static final long RUNSTATE;
-    private static final int ABASE;
-    private static final int ASHIFT;
+    // VarHandle mechanics
+    private static final VarHandle CTL;
+    private static final VarHandle MODE;
+    static final VarHandle QA;
 
     static {
         try {
-            CTL = U.objectFieldOffset
-                (ForkJoinPool.class.getDeclaredField("ctl"));
-            RUNSTATE = U.objectFieldOffset
-                (ForkJoinPool.class.getDeclaredField("runState"));
-            ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
-            int scale = U.arrayIndexScale(ForkJoinTask[].class);
-            if ((scale & (scale - 1)) != 0)
-                throw new Error("array index scale not a power of two");
-            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            CTL = l.findVarHandle(ForkJoinPool.class, "ctl", long.class);
+            MODE = l.findVarHandle(ForkJoinPool.class, "mode", int.class);
+            QA = MethodHandles.arrayElementVarHandle(ForkJoinTask[].class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
@@ -3498,52 +3197,11 @@
             new DefaultForkJoinWorkerThreadFactory();
         modifyThreadPermission = new RuntimePermission("modifyThread");
 
-        common = java.security.AccessController.doPrivileged
-            (new java.security.PrivilegedAction<ForkJoinPool>() {
-                public ForkJoinPool run() { return makeCommonPool(); }});
+        common = AccessController.doPrivileged(new PrivilegedAction<>() {
+            public ForkJoinPool run() {
+                return new ForkJoinPool((byte)0); }});
 
-        // report 1 even if threads disabled
-        COMMON_PARALLELISM = Math.max(common.config & SMASK, 1);
-    }
-
-    /**
-     * Creates and returns the common pool, respecting user settings
-     * specified via system properties.
-     */
-    static ForkJoinPool makeCommonPool() {
-        int parallelism = -1;
-        ForkJoinWorkerThreadFactory factory = null;
-        UncaughtExceptionHandler handler = null;
-        try {  // ignore exceptions in accessing/parsing properties
-            String pp = System.getProperty
-                ("java.util.concurrent.ForkJoinPool.common.parallelism");
-            String fp = System.getProperty
-                ("java.util.concurrent.ForkJoinPool.common.threadFactory");
-            String hp = System.getProperty
-                ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
-            if (pp != null)
-                parallelism = Integer.parseInt(pp);
-            if (fp != null)
-                factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
-                           getSystemClassLoader().loadClass(fp).newInstance());
-            if (hp != null)
-                handler = ((UncaughtExceptionHandler)ClassLoader.
-                           getSystemClassLoader().loadClass(hp).newInstance());
-        } catch (Exception ignore) {
-        }
-        if (factory == null) {
-            if (System.getSecurityManager() == null)
-                factory = defaultForkJoinWorkerThreadFactory;
-            else // use security-managed default
-                factory = new InnocuousForkJoinWorkerThreadFactory();
-        }
-        if (parallelism < 0 && // default 1 less than #cores
-            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
-            parallelism = 1;
-        if (parallelism > MAX_CAP)
-            parallelism = MAX_CAP;
-        return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
-                                "ForkJoinPool.commonPool-worker-");
+        COMMON_PARALLELISM = Math.max(common.mode & SMASK, 1);
     }
 
     /**
@@ -3556,27 +3214,20 @@
          * An ACC to restrict permissions for the factory itself.
          * The constructed workers have no permissions set.
          */
-        private static final AccessControlContext innocuousAcc;
-        static {
-            Permissions innocuousPerms = new Permissions();
-            innocuousPerms.add(modifyThreadPermission);
-            innocuousPerms.add(new RuntimePermission(
-                                   "enableContextClassLoaderOverride"));
-            innocuousPerms.add(new RuntimePermission(
-                                   "modifyThreadGroup"));
-            innocuousAcc = new AccessControlContext(new ProtectionDomain[] {
-                    new ProtectionDomain(null, innocuousPerms)
-                });
-        }
+        private static final AccessControlContext ACC = contextWithPermissions(
+            modifyThreadPermission,
+            new RuntimePermission("enableContextClassLoaderOverride"),
+            new RuntimePermission("modifyThreadGroup"),
+            new RuntimePermission("getClassLoader"),
+            new RuntimePermission("setContextClassLoader"));
 
         public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
-            return java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<ForkJoinWorkerThread>() {
+            return AccessController.doPrivileged(
+                new PrivilegedAction<>() {
                     public ForkJoinWorkerThread run() {
                         return new ForkJoinWorkerThread.
-                            InnocuousForkJoinWorkerThread(pool);
-                    }}, innocuousAcc);
+                            InnocuousForkJoinWorkerThread(pool); }},
+                ACC);
         }
     }
-
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
index efccfa5..fd28e84 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -36,6 +36,8 @@
 package java.util.concurrent;
 
 import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
@@ -96,7 +98,7 @@
  * encountering the exception; minimally only the latter.
  *
  * <p>It is possible to define and use ForkJoinTasks that may block,
- * but doing do requires three further considerations: (1) Completion
+ * but doing so requires three further considerations: (1) Completion
  * of few if any <em>other</em> tasks should be dependent on a task
  * that blocks on external synchronization or I/O. Event-style async
  * tasks that are never joined (for example, those subclassing {@link
@@ -136,11 +138,11 @@
  * {@link #isCompletedNormally} is true if a task completed without
  * cancellation or encountering an exception; {@link #isCancelled} is
  * true if the task was cancelled (in which case {@link #getException}
- * returns a {@link java.util.concurrent.CancellationException}); and
+ * returns a {@link CancellationException}); and
  * {@link #isCompletedAbnormally} is true if a task was either
  * cancelled or encountered an exception, in which case {@link
  * #getException} will return either the encountered exception or
- * {@link java.util.concurrent.CancellationException}.
+ * {@link CancellationException}.
  *
  * <p>The ForkJoinTask class is not usually directly subclassed.
  * Instead, you subclass one of the abstract classes that support a
@@ -221,52 +223,59 @@
      * methods in a way that flows well in javadocs.
      */
 
-    /*
+    /**
      * The status field holds run control status bits packed into a
-     * single int to minimize footprint and to ensure atomicity (via
-     * CAS).  Status is initially zero, and takes on nonnegative
-     * values until completed, upon which status (anded with
-     * DONE_MASK) holds value NORMAL, CANCELLED, or EXCEPTIONAL. Tasks
-     * undergoing blocking waits by other threads have the SIGNAL bit
-     * set.  Completion of a stolen task with SIGNAL set awakens any
-     * waiters via notifyAll. Even though suboptimal for some
-     * purposes, we use basic builtin wait/notify to take advantage of
-     * "monitor inflation" in JVMs that we would otherwise need to
-     * emulate to avoid adding further per-task bookkeeping overhead.
-     * We want these monitors to be "fat", i.e., not use biasing or
-     * thin-lock techniques, so use some odd coding idioms that tend
-     * to avoid them, mainly by arranging that every synchronized
-     * block performs a wait, notifyAll or both.
+     * single int to ensure atomicity.  Status is initially zero, and
+     * takes on nonnegative values until completed, upon which it
+     * holds (sign bit) DONE, possibly with ABNORMAL (cancelled or
+     * exceptional) and THROWN (in which case an exception has been
+     * stored). Tasks with dependent blocked waiting joiners have the
+     * SIGNAL bit set.  Completion of a task with SIGNAL set awakens
+     * any waiters via notifyAll. (Waiters also help signal others
+     * upon completion.)
      *
      * These control bits occupy only (some of) the upper half (16
      * bits) of status field. The lower bits are used for user-defined
      * tags.
      */
-
-    /** The run status of this task */
     volatile int status; // accessed directly by pool and workers
-    static final int DONE_MASK   = 0xf0000000;  // mask out non-completion bits
-    static final int NORMAL      = 0xf0000000;  // must be negative
-    static final int CANCELLED   = 0xc0000000;  // must be < NORMAL
-    static final int EXCEPTIONAL = 0x80000000;  // must be < CANCELLED
-    static final int SIGNAL      = 0x00010000;  // must be >= 1 << 16
-    static final int SMASK       = 0x0000ffff;  // short bits for tags
+
+    private static final int DONE     = 1 << 31; // must be negative
+    private static final int ABNORMAL = 1 << 18; // set atomically with DONE
+    private static final int THROWN   = 1 << 17; // set atomically with ABNORMAL
+    private static final int SIGNAL   = 1 << 16; // true if joiner waiting
+    private static final int SMASK    = 0xffff;  // short bits for tags
+
+    static boolean isExceptionalStatus(int s) {  // needed by subclasses
+        return (s & THROWN) != 0;
+    }
 
     /**
-     * Marks completion and wakes up threads waiting to join this
-     * task.
+     * Sets DONE status and wakes up threads waiting to join this task.
      *
-     * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
-     * @return completion status on exit
+     * @return status on exit
      */
-    private int setCompletion(int completion) {
-        for (int s;;) {
+    private int setDone() {
+        int s;
+        if (((s = (int)STATUS.getAndBitwiseOr(this, DONE)) & SIGNAL) != 0)
+            synchronized (this) { notifyAll(); }
+        return s | DONE;
+    }
+
+    /**
+     * Marks cancelled or exceptional completion unless already done.
+     *
+     * @param completion must be DONE | ABNORMAL, ORed with THROWN if exceptional
+     * @return status on exit
+     */
+    private int abnormalCompletion(int completion) {
+        for (int s, ns;;) {
             if ((s = status) < 0)
                 return s;
-            if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
-                if ((s >>> 16) != 0)
+            else if (STATUS.weakCompareAndSet(this, s, ns = s | completion)) {
+                if ((s & SIGNAL) != 0)
                     synchronized (this) { notifyAll(); }
-                return completion;
+                return ns;
             }
         }
     }
@@ -284,10 +293,11 @@
             try {
                 completed = exec();
             } catch (Throwable rex) {
-                return setExceptionalCompletion(rex);
+                completed = false;
+                s = setExceptionalCompletion(rex);
             }
             if (completed)
-                s = setCompletion(NORMAL);
+                s = setDone();
         }
         return s;
     }
@@ -299,9 +309,7 @@
      * @param timeout using Object.wait conventions.
      */
     final void internalWait(long timeout) {
-        int s;
-        if ((s = status) >= 0 && // force completer to issue notify
-            U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+        if ((int)STATUS.getAndBitwiseOr(this, SIGNAL) >= 0) {
             synchronized (this) {
                 if (status >= 0)
                     try { wait(timeout); } catch (InterruptedException ie) { }
@@ -316,27 +324,24 @@
      * @return status upon completion
      */
     private int externalAwaitDone() {
-        int s = ((this instanceof CountedCompleter) ? // try helping
-                 ForkJoinPool.common.externalHelpComplete(
-                     (CountedCompleter<?>)this, 0) :
-                 ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
-        if (s >= 0 && (s = status) >= 0) {
+        int s = tryExternalHelp();
+        if (s >= 0 && (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
             boolean interrupted = false;
-            do {
-                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
-                    synchronized (this) {
-                        if (status >= 0) {
-                            try {
-                                wait(0L);
-                            } catch (InterruptedException ie) {
-                                interrupted = true;
-                            }
+            synchronized (this) {
+                for (;;) {
+                    if ((s = status) >= 0) {
+                        try {
+                            wait(0L);
+                        } catch (InterruptedException ie) {
+                            interrupted = true;
                         }
-                        else
-                            notifyAll();
+                    }
+                    else {
+                        notifyAll();
+                        break;
                     }
                 }
-            } while ((s = status) >= 0);
+            }
             if (interrupted)
                 Thread.currentThread().interrupt();
         }
@@ -347,30 +352,40 @@
      * Blocks a non-worker-thread until completion or interruption.
      */
     private int externalInterruptibleAwaitDone() throws InterruptedException {
-        int s;
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        if ((s = status) >= 0 &&
-            (s = ((this instanceof CountedCompleter) ?
-                  ForkJoinPool.common.externalHelpComplete(
-                      (CountedCompleter<?>)this, 0) :
-                  ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
-                  0)) >= 0) {
-            while ((s = status) >= 0) {
-                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
-                    synchronized (this) {
-                        if (status >= 0)
-                            wait(0L);
-                        else
-                            notifyAll();
+        int s = tryExternalHelp();
+        if (s >= 0 && (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
+            synchronized (this) {
+                for (;;) {
+                    if ((s = status) >= 0)
+                        wait(0L);
+                    else {
+                        notifyAll();
+                        break;
                     }
                 }
             }
         }
+        else if (Thread.interrupted())
+            throw new InterruptedException();
         return s;
     }
 
     /**
+     * Tries to help with tasks allowed for external callers.
+     *
+     * @return current status
+     */
+    private int tryExternalHelp() {
+        int s;
+        return ((s = status) < 0 ? s:
+                (this instanceof CountedCompleter) ?
+                ForkJoinPool.common.externalHelpComplete(
+                    (CountedCompleter<?>)this, 0) :
+                ForkJoinPool.common.tryExternalUnpush(this) ?
+                doExec() : 0);
+    }
+
+    /**
      * Implementation for join, get, quietlyJoin. Directly handles
      * only cases of already-completed, external wait, and
      * unfork+exec.  Others are relayed to ForkJoinPool.awaitJoin.
@@ -404,22 +419,24 @@
     // Exception table support
 
     /**
-     * Table of exceptions thrown by tasks, to enable reporting by
-     * callers. Because exceptions are rare, we don't directly keep
+     * Hash table of exceptions thrown by tasks, to enable reporting
+     * by callers. Because exceptions are rare, we don't directly keep
      * them with task objects, but instead use a weak ref table.  Note
      * that cancellation exceptions don't appear in the table, but are
      * instead recorded as status values.
      *
-     * Note: These statics are initialized below in static block.
+     * The exception table has a fixed capacity.
      */
-    private static final ExceptionNode[] exceptionTable;
-    private static final ReentrantLock exceptionTableLock;
-    private static final ReferenceQueue<Object> exceptionTableRefQueue;
+    private static final ExceptionNode[] exceptionTable
+        = new ExceptionNode[32];
 
-    /**
-     * Fixed capacity for exceptionTable.
-     */
-    private static final int EXCEPTION_MAP_CAPACITY = 32;
+    /** Lock protecting access to exceptionTable. */
+    private static final ReentrantLock exceptionTableLock
+        = new ReentrantLock();
+
+    /** Reference queue of stale exceptionally completed tasks. */
+    private static final ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue
+        = new ReferenceQueue<>();
 
     /**
      * Key-value nodes for exception table.  The chained hash table
@@ -439,7 +456,7 @@
         final long thrower;  // use id not ref to avoid weak cycles
         final int hashCode;  // store task hashCode before weak ref disappears
         ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next,
-                      ReferenceQueue<Object> exceptionTableRefQueue) {
+                      ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue) {
             super(task, exceptionTableRefQueue);
             this.ex = ex;
             this.next = next;
@@ -475,7 +492,7 @@
             } finally {
                 lock.unlock();
             }
-            s = setCompletion(EXCEPTIONAL);
+            s = abnormalCompletion(DONE | ABNORMAL | THROWN);
         }
         return s;
     }
@@ -487,7 +504,7 @@
      */
     private int setExceptionalCompletion(Throwable ex) {
         int s = recordExceptionalCompletion(ex);
-        if ((s & DONE_MASK) == EXCEPTIONAL)
+        if ((s & THROWN) != 0)
             internalPropagateException(ex);
         return s;
     }
@@ -603,9 +620,8 @@
     private static void expungeStaleExceptions() {
         for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
             if (x instanceof ExceptionNode) {
-                int hashCode = ((ExceptionNode)x).hashCode;
                 ExceptionNode[] t = exceptionTable;
-                int i = hashCode & (t.length - 1);
+                int i = ((ExceptionNode)x).hashCode & (t.length - 1);
                 ExceptionNode e = t[i];
                 ExceptionNode pred = null;
                 while (e != null) {
@@ -663,10 +679,8 @@
      * Throws exception, if any, associated with the given status.
      */
     private void reportException(int s) {
-        if (s == CANCELLED)
-            throw new CancellationException();
-        if (s == EXCEPTIONAL)
-            rethrow(getThrowableException());
+        rethrow((s & THROWN) != 0 ? getThrowableException() :
+                new CancellationException());
     }
 
     // public methods
@@ -696,19 +710,19 @@
     }
 
     /**
-     * Returns the result of the computation when it {@link #isDone is
-     * done}.  This method differs from {@link #get()} in that
-     * abnormal completion results in {@code RuntimeException} or
-     * {@code Error}, not {@code ExecutionException}, and that
-     * interrupts of the calling thread do <em>not</em> cause the
-     * method to abruptly return by throwing {@code
-     * InterruptedException}.
+     * Returns the result of the computation when it
+     * {@linkplain #isDone is done}.
+     * This method differs from {@link #get()} in that abnormal
+     * completion results in {@code RuntimeException} or {@code Error},
+     * not {@code ExecutionException}, and that interrupts of the
+     * calling thread do <em>not</em> cause the method to abruptly
+     * return by throwing {@code InterruptedException}.
      *
      * @return the computed result
      */
     public final V join() {
         int s;
-        if ((s = doJoin() & DONE_MASK) != NORMAL)
+        if (((s = doJoin()) & ABNORMAL) != 0)
             reportException(s);
         return getRawResult();
     }
@@ -723,7 +737,7 @@
      */
     public final V invoke() {
         int s;
-        if ((s = doInvoke() & DONE_MASK) != NORMAL)
+        if (((s = doInvoke()) & ABNORMAL) != 0)
             reportException(s);
         return getRawResult();
     }
@@ -748,9 +762,9 @@
     public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
         int s1, s2;
         t2.fork();
-        if ((s1 = t1.doInvoke() & DONE_MASK) != NORMAL)
+        if (((s1 = t1.doInvoke()) & ABNORMAL) != 0)
             t1.reportException(s1);
-        if ((s2 = t2.doJoin() & DONE_MASK) != NORMAL)
+        if (((s2 = t2.doJoin()) & ABNORMAL) != 0)
             t2.reportException(s2);
     }
 
@@ -780,7 +794,7 @@
             }
             else if (i != 0)
                 t.fork();
-            else if (t.doInvoke() < NORMAL && ex == null)
+            else if ((t.doInvoke() & ABNORMAL) != 0 && ex == null)
                 ex = t.getException();
         }
         for (int i = 1; i <= last; ++i) {
@@ -788,7 +802,7 @@
             if (t != null) {
                 if (ex != null)
                     t.cancel(false);
-                else if (t.doJoin() < NORMAL)
+                else if ((t.doJoin() & ABNORMAL) != 0)
                     ex = t.getException();
             }
         }
@@ -816,7 +830,7 @@
      */
     public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) {
         if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) {
-            invokeAll(tasks.toArray(new ForkJoinTask<?>[tasks.size()]));
+            invokeAll(tasks.toArray(new ForkJoinTask<?>[0]));
             return tasks;
         }
         @SuppressWarnings("unchecked")
@@ -832,7 +846,7 @@
             }
             else if (i != 0)
                 t.fork();
-            else if (t.doInvoke() < NORMAL && ex == null)
+            else if ((t.doInvoke() & ABNORMAL) != 0 && ex == null)
                 ex = t.getException();
         }
         for (int i = 1; i <= last; ++i) {
@@ -840,7 +854,7 @@
             if (t != null) {
                 if (ex != null)
                     t.cancel(false);
-                else if (t.doJoin() < NORMAL)
+                else if ((t.doJoin() & ABNORMAL) != 0)
                     ex = t.getException();
             }
         }
@@ -877,7 +891,8 @@
      * @return {@code true} if this task is now cancelled
      */
     public boolean cancel(boolean mayInterruptIfRunning) {
-        return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED;
+        int s = abnormalCompletion(DONE | ABNORMAL);
+        return (s & (ABNORMAL | THROWN)) == ABNORMAL;
     }
 
     public final boolean isDone() {
@@ -885,7 +900,7 @@
     }
 
     public final boolean isCancelled() {
-        return (status & DONE_MASK) == CANCELLED;
+        return (status & (ABNORMAL | THROWN)) == ABNORMAL;
     }
 
     /**
@@ -894,7 +909,7 @@
      * @return {@code true} if this task threw an exception or was cancelled
      */
     public final boolean isCompletedAbnormally() {
-        return status < NORMAL;
+        return (status & ABNORMAL) != 0;
     }
 
     /**
@@ -905,7 +920,7 @@
      * exception and was not cancelled
      */
     public final boolean isCompletedNormally() {
-        return (status & DONE_MASK) == NORMAL;
+        return (status & (DONE | ABNORMAL)) == DONE;
     }
 
     /**
@@ -916,9 +931,9 @@
      * @return the exception, or {@code null} if none
      */
     public final Throwable getException() {
-        int s = status & DONE_MASK;
-        return ((s >= NORMAL)    ? null :
-                (s == CANCELLED) ? new CancellationException() :
+        int s = status;
+        return ((s & ABNORMAL) == 0 ? null :
+                (s & THROWN)   == 0 ? new CancellationException() :
                 getThrowableException());
     }
 
@@ -962,7 +977,7 @@
             setExceptionalCompletion(rex);
             return;
         }
-        setCompletion(NORMAL);
+        setDone();
     }
 
     /**
@@ -974,7 +989,7 @@
      * @since 1.8
      */
     public final void quietlyComplete() {
-        setCompletion(NORMAL);
+        setDone();
     }
 
     /**
@@ -991,11 +1006,12 @@
     public final V get() throws InterruptedException, ExecutionException {
         int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
             doJoin() : externalInterruptibleAwaitDone();
-        if ((s &= DONE_MASK) == CANCELLED)
-            throw new CancellationException();
-        if (s == EXCEPTIONAL)
+        if ((s & THROWN) != 0)
             throw new ExecutionException(getThrowableException());
-        return getRawResult();
+        else if ((s & ABNORMAL) != 0)
+            throw new CancellationException();
+        else
+            return getRawResult();
     }
 
     /**
@@ -1035,7 +1051,7 @@
                 while ((s = status) >= 0 &&
                        (ns = deadline - System.nanoTime()) > 0L) {
                     if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
-                        U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                        (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
                         synchronized (this) {
                             if (status >= 0)
                                 wait(ms); // OK to throw InterruptedException
@@ -1047,15 +1063,13 @@
             }
         }
         if (s >= 0)
-            s = status;
-        if ((s &= DONE_MASK) != NORMAL) {
-            if (s == CANCELLED)
-                throw new CancellationException();
-            if (s != EXCEPTIONAL)
-                throw new TimeoutException();
+            throw new TimeoutException();
+        else if ((s & THROWN) != 0)
             throw new ExecutionException(getThrowableException());
-        }
-        return getRawResult();
+        else if ((s & ABNORMAL) != 0)
+            throw new CancellationException();
+        else
+            return getRawResult();
     }
 
     /**
@@ -1111,7 +1125,7 @@
      * setRawResult(null)}.
      */
     public void reinitialize() {
-        if ((status & DONE_MASK) == EXCEPTIONAL)
+        if ((status & THROWN) != 0)
             clearExceptionalCompletion();
         else
             status = 0;
@@ -1329,8 +1343,8 @@
      */
     public final short setForkJoinTaskTag(short newValue) {
         for (int s;;) {
-            if (U.compareAndSwapInt(this, STATUS, s = status,
-                                    (s & ~SMASK) | (newValue & SMASK)))
+            if (STATUS.weakCompareAndSet(this, s = status,
+                                         (s & ~SMASK) | (newValue & SMASK)))
                 return (short)s;
         }
     }
@@ -1353,8 +1367,8 @@
         for (int s;;) {
             if ((short)(s = status) != expect)
                 return false;
-            if (U.compareAndSwapInt(this, STATUS, s,
-                                    (s & ~SMASK) | (update & SMASK)))
+            if (STATUS.weakCompareAndSet(this, s,
+                                         (s & ~SMASK) | (update & SMASK)))
                 return true;
         }
     }
@@ -1377,6 +1391,9 @@
         public final void setRawResult(T v) { result = v; }
         public final boolean exec() { runnable.run(); return true; }
         public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + runnable + "]";
+        }
         private static final long serialVersionUID = 5232453952276885070L;
     }
 
@@ -1394,6 +1411,9 @@
         public final void setRawResult(Void v) { }
         public final boolean exec() { runnable.run(); return true; }
         public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + runnable + "]";
+        }
         private static final long serialVersionUID = 5232453952276885070L;
     }
 
@@ -1439,6 +1459,9 @@
             }
         }
         public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + callable + "]";
+        }
         private static final long serialVersionUID = 2838392045355241008L;
     }
 
@@ -1515,19 +1538,14 @@
             setExceptionalCompletion((Throwable)ex);
     }
 
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long STATUS;
-
+    // VarHandle mechanics
+    private static final VarHandle STATUS;
     static {
-        exceptionTableLock = new ReentrantLock();
-        exceptionTableRefQueue = new ReferenceQueue<Object>();
-        exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
         try {
-            STATUS = U.objectFieldOffset
-                (ForkJoinTask.class.getDeclaredField("status"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATUS = l.findVarHandle(ForkJoinTask.class, "status", int.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
index e98ba99..fa47c22 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
@@ -36,6 +36,8 @@
 package java.util.concurrent;
 
 import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 
 /**
@@ -47,7 +49,9 @@
  * and termination methods surrounding the main task processing loop.
  * If you do create such a subclass, you will also need to supply a
  * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
- * {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
+ * {@linkplain ForkJoinPool#ForkJoinPool(int, ForkJoinWorkerThreadFactory,
+ * UncaughtExceptionHandler, boolean, int, int, int, Predicate, long, TimeUnit)
+ * use it} in a {@code ForkJoinPool}.
  *
  * @since 1.7
  * @author Doug Lea
@@ -66,8 +70,9 @@
      * owning thread.
      *
      * Support for (non-public) subclass InnocuousForkJoinWorkerThread
-     * requires that we break quite a lot of encapsulation (via Unsafe)
-     * both here and in the subclass to access and set Thread fields.
+     * requires that we break quite a lot of encapsulation (via helper
+     * methods in ThreadLocalRandom) both here and in the subclass to
+     * access and set Thread fields.
      */
 
     final ForkJoinPool pool;                // the pool this thread works in
@@ -87,13 +92,28 @@
     }
 
     /**
+     * Version for use by the default pool.  Supports setting the
+     * context class loader.  This is a separate constructor to avoid
+     * affecting the protected constructor.
+     */
+    ForkJoinWorkerThread(ForkJoinPool pool, ClassLoader ccl) {
+        super("aForkJoinWorkerThread");
+        super.setContextClassLoader(ccl);
+        this.pool = pool;
+        this.workQueue = pool.registerWorker(this);
+    }
+
+    /**
      * Version for InnocuousForkJoinWorkerThread.
      */
-    ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
+    ForkJoinWorkerThread(ForkJoinPool pool,
+                         ClassLoader ccl,
+                         ThreadGroup threadGroup,
                          AccessControlContext acc) {
         super(threadGroup, null, "aForkJoinWorkerThread");
-        U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
-        eraseThreadLocals(); // clear before registering
+        super.setContextClassLoader(ccl);
+        ThreadLocalRandom.setInheritedAccessControlContext(this, acc);
+        ThreadLocalRandom.eraseThreadLocals(this); // clear before registering
         this.pool = pool;
         this.workQueue = pool.registerWorker(this);
     }
@@ -171,66 +191,44 @@
     }
 
     /**
-     * Erases ThreadLocals by nulling out Thread maps.
-     */
-    final void eraseThreadLocals() {
-        U.putObject(this, THREADLOCALS, null);
-        U.putObject(this, INHERITABLETHREADLOCALS, null);
-    }
-
-    /**
      * Non-public hook method for InnocuousForkJoinWorkerThread.
      */
     void afterTopLevelExec() {
     }
 
-    // Set up to allow setting thread fields in constructor
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long THREADLOCALS;
-    private static final long INHERITABLETHREADLOCALS;
-    private static final long INHERITEDACCESSCONTROLCONTEXT;
-    static {
-        try {
-            THREADLOCALS = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocals"));
-            INHERITABLETHREADLOCALS = U.objectFieldOffset
-                (Thread.class.getDeclaredField("inheritableThreadLocals"));
-            INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
-                (Thread.class.getDeclaredField("inheritedAccessControlContext"));
-        } catch (ReflectiveOperationException e) {
-            throw new Error(e);
-        }
-    }
-
     /**
      * A worker thread that has no permissions, is not a member of any
-     * user-defined ThreadGroup, and erases all ThreadLocals after
+     * user-defined ThreadGroup, uses the system class loader as
+     * thread context class loader, and erases all ThreadLocals after
      * running each top-level task.
      */
     static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
         /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
         private static final ThreadGroup innocuousThreadGroup =
-            createThreadGroup();
+            AccessController.doPrivileged(new PrivilegedAction<>() {
+                public ThreadGroup run() {
+                    ThreadGroup group = Thread.currentThread().getThreadGroup();
+                    for (ThreadGroup p; (p = group.getParent()) != null; )
+                        group = p;
+                    return new ThreadGroup(
+                        group, "InnocuousForkJoinWorkerThreadGroup");
+                }});
 
         /** An AccessControlContext supporting no privileges */
         private static final AccessControlContext INNOCUOUS_ACC =
             new AccessControlContext(
-                new ProtectionDomain[] {
-                    new ProtectionDomain(null, null)
-                });
+                new ProtectionDomain[] { new ProtectionDomain(null, null) });
 
         InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
-            super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
+            super(pool,
+                  ClassLoader.getSystemClassLoader(),
+                  innocuousThreadGroup,
+                  INNOCUOUS_ACC);
         }
 
         @Override // to erase ThreadLocals
         void afterTopLevelExec() {
-            eraseThreadLocals();
-        }
-
-        @Override // to always report system loader
-        public ClassLoader getContextClassLoader() {
-            return ClassLoader.getSystemClassLoader();
+            ThreadLocalRandom.eraseThreadLocals(this);
         }
 
         @Override // to silently fail
@@ -240,34 +238,5 @@
         public void setContextClassLoader(ClassLoader cl) {
             throw new SecurityException("setContextClassLoader");
         }
-
-        /**
-         * Returns a new group with the system ThreadGroup (the
-         * topmost, parent-less group) as parent.  Uses Unsafe to
-         * traverse Thread.group and ThreadGroup.parent fields.
-         */
-        private static ThreadGroup createThreadGroup() {
-            try {
-                sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
-                long tg = u.objectFieldOffset
-                    (Thread.class.getDeclaredField("group"));
-                long gp = u.objectFieldOffset
-                    (ThreadGroup.class.getDeclaredField("parent"));
-                ThreadGroup group = (ThreadGroup)
-                    u.getObject(Thread.currentThread(), tg);
-                while (group != null) {
-                    ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
-                    if (parent == null)
-                        return new ThreadGroup(group,
-                                               "InnocuousForkJoinWorkerThreadGroup");
-                    group = parent;
-                }
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-            // fall through if null as cannot-happen safeguard
-            throw new Error("Cannot create ThreadGroup");
-        }
     }
-
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/Future.java b/ojluni/src/main/java/java/util/concurrent/Future.java
index 9bd05d6..6099c7c 100644
--- a/ojluni/src/main/java/java/util/concurrent/Future.java
+++ b/ojluni/src/main/java/java/util/concurrent/Future.java
@@ -50,8 +50,7 @@
  * declare types of the form {@code Future<?>} and
  * return {@code null} as a result of the underlying task.
  *
- * <p>
- * <b>Sample Usage</b> (Note that the following classes are all
+ * <p><b>Sample Usage</b> (Note that the following classes are all
  * made-up.)
  *
  * <pre> {@code
@@ -59,13 +58,9 @@
  * class App {
  *   ExecutorService executor = ...
  *   ArchiveSearcher searcher = ...
- *   void showSearch(final String target)
- *       throws InterruptedException {
- *     Future<String> future
- *       = executor.submit(new Callable<String>() {
- *         public String call() {
- *             return searcher.search(target);
- *         }});
+ *   void showSearch(String target) throws InterruptedException {
+ *     Callable<String> task = () -> searcher.search(target);
+ *     Future<String> future = executor.submit(task);
  *     displayOtherThings(); // do other things while searching
  *     try {
  *       displayText(future.get()); // use future
@@ -77,11 +72,7 @@
  * implements {@code Runnable}, and so may be executed by an {@code Executor}.
  * For example, the above construction with {@code submit} could be replaced by:
  * <pre> {@code
- * FutureTask<String> future =
- *   new FutureTask<>(new Callable<String>() {
- *     public String call() {
- *       return searcher.search(target);
- *   }});
+ * FutureTask<String> future = new FutureTask<>(task);
  * executor.execute(future);}</pre>
  *
  * <p>Memory consistency effects: Actions taken by the asynchronous computation
diff --git a/ojluni/src/main/java/java/util/concurrent/FutureTask.java b/ojluni/src/main/java/java/util/concurrent/FutureTask.java
index 62c2bfc..e913ef3 100644
--- a/ojluni/src/main/java/java/util/concurrent/FutureTask.java
+++ b/ojluni/src/main/java/java/util/concurrent/FutureTask.java
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.concurrent.locks.LockSupport;
 
 /**
@@ -69,9 +71,6 @@
      * cancellation races. Sync control in the current design relies
      * on a "state" field updated via CAS to track completion, along
      * with a simple Treiber stack to hold waiting threads.
-     *
-     * Style note: As usual, we bypass overhead of using
-     * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
      */
 
     /**
@@ -163,9 +162,8 @@
     }
 
     public boolean cancel(boolean mayInterruptIfRunning) {
-        if (!(state == NEW &&
-              U.compareAndSwapInt(this, STATE, NEW,
-                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
+        if (!(state == NEW && STATE.compareAndSet
+              (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
             return false;
         try {    // in case call to interrupt throws exception
             if (mayInterruptIfRunning) {
@@ -174,7 +172,7 @@
                     if (t != null)
                         t.interrupt();
                 } finally { // final state
-                    U.putOrderedInt(this, STATE, INTERRUPTED);
+                    STATE.setRelease(this, INTERRUPTED);
                 }
             }
         } finally {
@@ -228,9 +226,9 @@
      * @param v the value
      */
     protected void set(V v) {
-        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
             outcome = v;
-            U.putOrderedInt(this, STATE, NORMAL); // final state
+            STATE.setRelease(this, NORMAL); // final state
             finishCompletion();
         }
     }
@@ -246,16 +244,16 @@
      * @param t the cause of failure
      */
     protected void setException(Throwable t) {
-        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
             outcome = t;
-            U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
+            STATE.setRelease(this, EXCEPTIONAL); // final state
             finishCompletion();
         }
     }
 
     public void run() {
         if (state != NEW ||
-            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
             return;
         try {
             Callable<V> c = callable;
@@ -296,7 +294,7 @@
      */
     protected boolean runAndReset() {
         if (state != NEW ||
-            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
             return false;
         boolean ran = false;
         int s = state;
@@ -363,7 +361,7 @@
     private void finishCompletion() {
         // assert state > COMPLETING;
         for (WaitNode q; (q = waiters) != null;) {
-            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
+            if (WAITERS.weakCompareAndSet(this, q, null)) {
                 for (;;) {
                     Thread t = q.thread;
                     if (t != null) {
@@ -425,8 +423,7 @@
                 q = new WaitNode();
             }
             else if (!queued)
-                queued = U.compareAndSwapObject(this, WAITERS,
-                                                q.next = waiters, q);
+                queued = WAITERS.weakCompareAndSet(this, q.next = waiters, q);
             else if (timed) {
                 final long parkNanos;
                 if (startTime == 0L) { // first time
@@ -475,7 +472,7 @@
                         if (pred.thread == null) // check for race
                             continue retry;
                     }
-                    else if (!U.compareAndSwapObject(this, WAITERS, q, s))
+                    else if (!WAITERS.compareAndSet(this, q, s))
                         continue retry;
                 }
                 break;
@@ -483,21 +480,53 @@
         }
     }
 
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long STATE;
-    private static final long RUNNER;
-    private static final long WAITERS;
+    /**
+     * Returns a string representation of this FutureTask.
+     *
+     * @implSpec
+     * The default implementation returns a string identifying this
+     * FutureTask, as well as its completion state.  The state, in
+     * brackets, contains one of the strings {@code "Completed Normally"},
+     * {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
+     * "Not completed"}.
+     *
+     * @return a string representation of this FutureTask
+     */
+    public String toString() {
+        final String status;
+        switch (state) {
+        case NORMAL:
+            status = "[Completed normally]";
+            break;
+        case EXCEPTIONAL:
+            status = "[Completed exceptionally: " + outcome + "]";
+            break;
+        case CANCELLED:
+        case INTERRUPTING:
+        case INTERRUPTED:
+            status = "[Cancelled]";
+            break;
+        default:
+            final Callable<?> callable = this.callable;
+            status = (callable == null)
+                ? "[Not completed]"
+                : "[Not completed, task = " + callable + "]";
+        }
+        return super.toString() + status;
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle STATE;
+    private static final VarHandle RUNNER;
+    private static final VarHandle WAITERS;
     static {
         try {
-            STATE = U.objectFieldOffset
-                (FutureTask.class.getDeclaredField("state"));
-            RUNNER = U.objectFieldOffset
-                (FutureTask.class.getDeclaredField("runner"));
-            WAITERS = U.objectFieldOffset
-                (FutureTask.class.getDeclaredField("waiters"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(FutureTask.class, "state", int.class);
+            RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
+            WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
index 9829c9c..f55998e 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
@@ -39,15 +39,13 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
 
 /**
  * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
@@ -66,9 +64,12 @@
  * contains}, {@link #iterator iterator.remove()}, and the bulk
  * operations, all of which run in linear time.
  *
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
  *
  * @since 1.6
  * @author  Doug Lea
@@ -194,18 +195,7 @@
      */
     public LinkedBlockingDeque(Collection<? extends E> c) {
         this(Integer.MAX_VALUE);
-        final ReentrantLock lock = this.lock;
-        lock.lock(); // Never contended, but necessary for visibility
-        try {
-            for (E e : c) {
-                if (e == null)
-                    throw new NullPointerException();
-                if (!linkLast(new Node<E>(e)))
-                    throw new IllegalStateException("Deque full");
-            }
-        } finally {
-            lock.unlock();
-        }
+        addAll(c);
     }
 
 
@@ -298,6 +288,7 @@
      */
     void unlink(Node<E> x) {
         // assert lock.isHeldByCurrentThread();
+        // assert x.item != null;
         Node<E> p = x.prev;
         Node<E> n = x.next;
         if (p == null) {
@@ -660,7 +651,7 @@
 
     /**
      * Retrieves and removes the head of the queue represented by this deque.
-     * This method differs from {@link #poll poll} only in that it throws an
+     * This method differs from {@link #poll() poll()} only in that it throws an
      * exception if this deque is empty.
      *
      * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
@@ -686,7 +677,7 @@
 
     /**
      * Retrieves, but does not remove, the head of the queue represented by
-     * this deque.  This method differs from {@link #peek peek} only in that
+     * this deque.  This method differs from {@link #peek() peek()} only in that
      * it throws an exception if this deque is empty.
      *
      * <p>This method is equivalent to {@link #getFirst() getFirst}.
@@ -740,8 +731,7 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        if (c == null)
-            throw new NullPointerException();
+        Objects.requireNonNull(c);
         if (c == this)
             throw new IllegalArgumentException();
         if (maxElements <= 0)
@@ -834,46 +824,65 @@
         }
     }
 
-    /*
-     * TODO: Add support for more efficient bulk operations.
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this deque, in the order that they are returned by the specified
+     * collection's iterator.  Attempts to {@code addAll} of a deque to
+     * itself result in {@code IllegalArgumentException}.
      *
-     * We don't want to acquire the lock for every iteration, but we
-     * also want other threads a chance to interact with the
-     * collection, especially when count is close to capacity.
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     * @throws IllegalArgumentException if the collection is this deque
+     * @throws IllegalStateException if this deque is full
+     * @see #add(Object)
      */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == this)
+            // As historically specified in AbstractQueue#addAll
+            throw new IllegalArgumentException();
 
-//     /**
-//      * Adds all of the elements in the specified collection to this
-//      * queue.  Attempts to addAll of a queue to itself result in
-//      * {@code IllegalArgumentException}. Further, 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 queue
-//      * @return {@code true} if this queue changed as a result of the call
-//      * @throws ClassCastException            {@inheritDoc}
-//      * @throws NullPointerException          {@inheritDoc}
-//      * @throws IllegalArgumentException      {@inheritDoc}
-//      * @throws IllegalStateException if this deque is full
-//      * @see #add(Object)
-//      */
-//     public boolean addAll(Collection<? extends E> c) {
-//         if (c == null)
-//             throw new NullPointerException();
-//         if (c == this)
-//             throw new IllegalArgumentException();
-//         final ReentrantLock lock = this.lock;
-//         lock.lock();
-//         try {
-//             boolean modified = false;
-//             for (E e : c)
-//                 if (linkLast(e))
-//                     modified = true;
-//             return modified;
-//         } finally {
-//             lock.unlock();
-//         }
-//     }
+        // Copy c into a private chain of Nodes
+        Node<E> beg = null, end = null;
+        int n = 0;
+        for (E e : c) {
+            Objects.requireNonNull(e);
+            n++;
+            Node<E> newNode = new Node<E>(e);
+            if (beg == null)
+                beg = end = newNode;
+            else {
+                end.next = newNode;
+                newNode.prev = end;
+                end = newNode;
+            }
+        }
+        if (beg == null)
+            return false;
+
+        // Atomically append the chain at the end
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count + n <= capacity) {
+                beg.prev = last;
+                if (first == null)
+                    first = beg;
+                else
+                    last.next = beg;
+                last = end;
+                count += n;
+                notEmpty.signalAll();
+                return true;
+            }
+        } finally {
+            lock.unlock();
+        }
+        // Fall back to historic non-atomic implementation, failing
+        // with IllegalStateException when the capacity is exceeded.
+        return super.addAll(c);
+    }
 
     /**
      * Returns an array containing all of the elements in this deque, in
@@ -986,6 +995,18 @@
     }
 
     /**
+     * Used for any element traversal that is not entirely under lock.
+     * Such traversals must handle both:
+     * - dequeued nodes (p.next == p)
+     * - (possibly multiple) interior removed nodes (p.item == null)
+     */
+    Node<E> succ(Node<E> p) {
+        if (p == (p = p.next))
+            p = first;
+        return p;
+    }
+
+    /**
      * Returns an iterator over the elements in this deque in proper sequence.
      * The elements will be returned in order from first (head) to last (tail).
      *
@@ -1024,8 +1045,8 @@
         /**
          * nextItem holds on to item fields because once we claim that
          * an element exists in hasNext(), we must return item read
-         * under lock (in advance()) even if it was in the process of
-         * being removed when hasNext() was called.
+         * under lock even if it was in the process of being removed
+         * when hasNext() was called.
          */
         E nextItem;
 
@@ -1038,48 +1059,19 @@
         abstract Node<E> firstNode();
         abstract Node<E> nextNode(Node<E> n);
 
+        private Node<E> succ(Node<E> p) {
+            if (p == (p = nextNode(p)))
+                p = firstNode();
+            return p;
+        }
+
         AbstractItr() {
             // set to initial position
             final ReentrantLock lock = LinkedBlockingDeque.this.lock;
             lock.lock();
             try {
-                next = firstNode();
-                nextItem = (next == null) ? null : next.item;
-            } finally {
-                lock.unlock();
-            }
-        }
-
-        /**
-         * Returns the successor node of the given non-null, but
-         * possibly previously deleted, node.
-         */
-        private Node<E> succ(Node<E> n) {
-            // Chains of deleted nodes ending in null or self-links
-            // are possible if multiple interior nodes are removed.
-            for (;;) {
-                Node<E> s = nextNode(n);
-                if (s == null)
-                    return null;
-                else if (s.item != null)
-                    return s;
-                else if (s == n)
-                    return firstNode();
-                else
-                    n = s;
-            }
-        }
-
-        /**
-         * Advances next.
-         */
-        void advance() {
-            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
-            lock.lock();
-            try {
-                // assert next != null;
-                next = succ(next);
-                nextItem = (next == null) ? null : next.item;
+                if ((next = firstNode()) != null)
+                    nextItem = next.item;
             } finally {
                 lock.unlock();
             }
@@ -1090,14 +1082,65 @@
         }
 
         public E next() {
-            if (next == null)
+            Node<E> p;
+            if ((p = next) == null)
                 throw new NoSuchElementException();
-            lastRet = next;
+            lastRet = p;
             E x = nextItem;
-            advance();
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                E e = null;
+                for (p = nextNode(p); p != null && (e = p.item) == null; )
+                    p = succ(p);
+                next = p;
+                nextItem = e;
+            } finally {
+                lock.unlock();
+            }
             return x;
         }
 
+        public void forEachRemaining(Consumer<? super E> action) {
+            // A variant of forEachFrom
+            Objects.requireNonNull(action);
+            Node<E> p;
+            if ((p = next) == null) return;
+            lastRet = p;
+            next = null;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            final int batchSize = 64;
+            Object[] es = null;
+            int n, len = 1;
+            do {
+                lock.lock();
+                try {
+                    if (es == null) {
+                        p = nextNode(p);
+                        for (Node<E> q = p; q != null; q = succ(q))
+                            if (q.item != null && ++len == batchSize)
+                                break;
+                        es = new Object[len];
+                        es[0] = nextItem;
+                        nextItem = null;
+                        n = 1;
+                    } else
+                        n = 0;
+                    for (; p != null && n < len; p = succ(p))
+                        if ((es[n] = p.item) != null) {
+                            lastRet = p;
+                            n++;
+                        }
+                } finally {
+                    lock.unlock();
+                }
+                for (int i = 0; i < n; i++) {
+                    @SuppressWarnings("unchecked") E e = (E) es[i];
+                    action.accept(e);
+                }
+            } while (n > 0 && p != null);
+        }
+
         public void remove() {
             Node<E> n = lastRet;
             if (n == null)
@@ -1116,51 +1159,49 @@
 
     /** Forward iterator */
     private class Itr extends AbstractItr {
+        Itr() {}                        // prevent access constructor creation
         Node<E> firstNode() { return first; }
         Node<E> nextNode(Node<E> n) { return n.next; }
     }
 
     /** Descending iterator */
     private class DescendingItr extends AbstractItr {
+        DescendingItr() {}              // prevent access constructor creation
         Node<E> firstNode() { return last; }
         Node<E> nextNode(Node<E> n) { return n.prev; }
     }
 
-    /** A customized variant of Spliterators.IteratorSpliterator */
-    static final class LBDSpliterator<E> implements Spliterator<E> {
+    /**
+     * A customized variant of Spliterators.IteratorSpliterator.
+     * Keep this class in sync with (very similar) LBQSpliterator.
+     */
+    private final class LBDSpliterator implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
-        final LinkedBlockingDeque<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
-        long est;           // size estimate
-        LBDSpliterator(LinkedBlockingDeque<E> queue) {
-            this.queue = queue;
-            this.est = queue.size();
-        }
+        long est = size();  // size estimate
+
+        LBDSpliterator() {}
 
         public long estimateSize() { return est; }
 
         public Spliterator<E> trySplit() {
             Node<E> h;
-            final LinkedBlockingDeque<E> q = this.queue;
-            int b = batch;
-            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
             if (!exhausted &&
-                ((h = current) != null || (h = q.first) != null) &&
-                h.next != null) {
+                ((h = current) != null || (h = first) != null)
+                && h.next != null) {
+                int n = batch = Math.min(batch + 1, MAX_BATCH);
                 Object[] a = new Object[n];
-                final ReentrantLock lock = q.lock;
+                final ReentrantLock lock = LinkedBlockingDeque.this.lock;
                 int i = 0;
                 Node<E> p = current;
                 lock.lock();
                 try {
-                    if (p != null || (p = q.first) != null) {
-                        do {
+                    if (p != null || (p = first) != null)
+                        for (; p != null && i < n; p = succ(p))
                             if ((a[i] = p.item) != null)
-                                ++i;
-                        } while ((p = p.next) != null && i < n);
-                    }
+                                i++;
                 } finally {
                     lock.unlock();
                 }
@@ -1170,66 +1211,33 @@
                 }
                 else if ((est -= i) < 0L)
                     est = 0L;
-                if (i > 0) {
-                    batch = i;
+                if (i > 0)
                     return Spliterators.spliterator
                         (a, 0, i, (Spliterator.ORDERED |
                                    Spliterator.NONNULL |
                                    Spliterator.CONCURRENT));
-                }
             }
             return null;
         }
 
-        public void forEachRemaining(Consumer<? super E> action) {
-            if (action == null) throw new NullPointerException();
-            final LinkedBlockingDeque<E> q = this.queue;
-            final ReentrantLock lock = q.lock;
-            if (!exhausted) {
-                exhausted = true;
-                Node<E> p = current;
-                do {
-                    E e = null;
-                    lock.lock();
-                    try {
-                        if (p == null)
-                            p = q.first;
-                        while (p != null) {
-                            e = p.item;
-                            p = p.next;
-                            if (e != null)
-                                break;
-                        }
-                    } finally {
-                        lock.unlock();
-                    }
-                    if (e != null)
-                        action.accept(e);
-                } while (p != null);
-            }
-        }
-
         public boolean tryAdvance(Consumer<? super E> action) {
-            if (action == null) throw new NullPointerException();
-            final LinkedBlockingDeque<E> q = this.queue;
-            final ReentrantLock lock = q.lock;
+            Objects.requireNonNull(action);
             if (!exhausted) {
                 E e = null;
+                final ReentrantLock lock = LinkedBlockingDeque.this.lock;
                 lock.lock();
                 try {
-                    if (current == null)
-                        current = q.first;
-                    while (current != null) {
-                        e = current.item;
-                        current = current.next;
-                        if (e != null)
-                            break;
-                    }
+                    Node<E> p;
+                    if ((p = current) != null || (p = first) != null)
+                        do {
+                            e = p.item;
+                            p = succ(p);
+                        } while (e == null && p != null);
+                    if ((current = p) == null)
+                        exhausted = true;
                 } finally {
                     lock.unlock();
                 }
-                if (current == null)
-                    exhausted = true;
                 if (e != null) {
                     action.accept(e);
                     return true;
@@ -1238,9 +1246,20 @@
             return false;
         }
 
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                current = null;
+                forEachFrom(action, p);
+            }
+        }
+
         public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.NONNULL |
-                Spliterator.CONCURRENT;
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
         }
     }
 
@@ -1261,7 +1280,127 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new LBDSpliterator<E>(this);
+        return new LBDSpliterator();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        forEachFrom(action, null);
+    }
+
+    /**
+     * Runs action on each element found during a traversal starting at p.
+     * If p is null, traversal starts at head.
+     */
+    void forEachFrom(Consumer<? super E> action, Node<E> p) {
+        // Extract batches of elements while holding the lock; then
+        // run the action on the elements while not
+        final ReentrantLock lock = this.lock;
+        final int batchSize = 64;       // max number of elements per batch
+        Object[] es = null;             // container for batch of elements
+        int n, len = 0;
+        do {
+            lock.lock();
+            try {
+                if (es == null) {
+                    if (p == null) p = first;
+                    for (Node<E> q = p; q != null; q = succ(q))
+                        if (q.item != null && ++len == batchSize)
+                            break;
+                    es = new Object[len];
+                }
+                for (n = 0; p != null && n < len; p = succ(p))
+                    if ((es[n] = p.item) != null)
+                        n++;
+            } finally {
+                lock.unlock();
+            }
+            for (int i = 0; i < n; i++) {
+                @SuppressWarnings("unchecked") E e = (E) es[i];
+                action.accept(e);
+            }
+        } while (n > 0 && p != null);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    @SuppressWarnings("unchecked")
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        final ReentrantLock lock = this.lock;
+        Node<E> p = null;
+        Node<E>[] nodes = null;
+        int n, len = 0;
+        do {
+            // 1. Extract batch of up to 64 elements while holding the lock.
+            lock.lock();
+            try {
+                if (nodes == null) {  // first batch; initialize
+                    p = first;
+                    for (Node<E> q = p; q != null; q = succ(q))
+                        if (q.item != null && ++len == 64)
+                            break;
+                    nodes = (Node<E>[]) new Node<?>[len];
+                }
+                for (n = 0; p != null && n < len; p = succ(p))
+                    nodes[n++] = p;
+            } finally {
+                lock.unlock();
+            }
+
+            // 2. Run the filter on the elements while lock is free.
+            long deathRow = 0L;       // "bitset" of size 64
+            for (int i = 0; i < n; i++) {
+                final E e;
+                if ((e = nodes[i].item) != null && filter.test(e))
+                    deathRow |= 1L << i;
+            }
+
+            // 3. Remove any filtered elements while holding the lock.
+            if (deathRow != 0) {
+                lock.lock();
+                try {
+                    for (int i = 0; i < n; i++) {
+                        final Node<E> q;
+                        if ((deathRow & (1L << i)) != 0L
+                            && (q = nodes[i]).item != null) {
+                            unlink(q);
+                            removed = true;
+                        }
+                        nodes[i] = null; // help GC
+                    }
+                } finally {
+                    lock.unlock();
+                }
+            }
+        } while (n > 0 && p != null);
+        return removed;
     }
 
     /**
@@ -1304,12 +1443,21 @@
         last = null;
         // Read in all elements and place in queue
         for (;;) {
-            @SuppressWarnings("unchecked")
-            E item = (E)s.readObject();
+            @SuppressWarnings("unchecked") E item = (E)s.readObject();
             if (item == null)
                 break;
             add(item);
         }
     }
 
+    void checkInvariants() {
+        // assert lock.isHeldByCurrentThread();
+        // Nodes may get self-linked or lose their item, but only
+        // after being unlinked and becoming unreachable from first.
+        for (Node<E> p = first; p != null; p = p.next) {
+            // assert p.next != p;
+            // assert p.item != null;
+        }
+    }
+
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
index cf2d447..4ba6c1e 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
@@ -39,16 +39,14 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
 
 /**
  * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
@@ -69,9 +67,12 @@
  * dynamically created upon each insertion unless this would bring the
  * queue above capacity.
  *
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
  *
  * @since 1.5
  * @author Doug Lea
@@ -234,14 +235,6 @@
         putLock.unlock();
     }
 
-//     /**
-//      * Tells whether both locks are held by current thread.
-//      */
-//     boolean isFullyLocked() {
-//         return (putLock.isHeldByCurrentThread() &&
-//                 takeLock.isHeldByCurrentThread());
-//     }
-
     /**
      * Creates a {@code LinkedBlockingQueue} with a capacity of
      * {@link Integer#MAX_VALUE}.
@@ -330,10 +323,8 @@
      */
     public void put(E e) throws InterruptedException {
         if (e == null) throw new NullPointerException();
-        // Note: convention in all put/take/etc is to preset local var
-        // holding count negative to indicate failure unless set.
-        int c = -1;
-        Node<E> node = new Node<E>(e);
+        final int c;
+        final Node<E> node = new Node<E>(e);
         final ReentrantLock putLock = this.putLock;
         final AtomicInteger count = this.count;
         putLock.lockInterruptibly();
@@ -374,7 +365,7 @@
 
         if (e == null) throw new NullPointerException();
         long nanos = unit.toNanos(timeout);
-        int c = -1;
+        final int c;
         final ReentrantLock putLock = this.putLock;
         final AtomicInteger count = this.count;
         putLock.lockInterruptibly();
@@ -412,28 +403,28 @@
         final AtomicInteger count = this.count;
         if (count.get() == capacity)
             return false;
-        int c = -1;
-        Node<E> node = new Node<E>(e);
+        final int c;
+        final Node<E> node = new Node<E>(e);
         final ReentrantLock putLock = this.putLock;
         putLock.lock();
         try {
-            if (count.get() < capacity) {
-                enqueue(node);
-                c = count.getAndIncrement();
-                if (c + 1 < capacity)
-                    notFull.signal();
-            }
+            if (count.get() == capacity)
+                return false;
+            enqueue(node);
+            c = count.getAndIncrement();
+            if (c + 1 < capacity)
+                notFull.signal();
         } finally {
             putLock.unlock();
         }
         if (c == 0)
             signalNotEmpty();
-        return c >= 0;
+        return true;
     }
 
     public E take() throws InterruptedException {
-        E x;
-        int c = -1;
+        final E x;
+        final int c;
         final AtomicInteger count = this.count;
         final ReentrantLock takeLock = this.takeLock;
         takeLock.lockInterruptibly();
@@ -454,8 +445,8 @@
     }
 
     public E poll(long timeout, TimeUnit unit) throws InterruptedException {
-        E x = null;
-        int c = -1;
+        final E x;
+        final int c;
         long nanos = unit.toNanos(timeout);
         final AtomicInteger count = this.count;
         final ReentrantLock takeLock = this.takeLock;
@@ -482,17 +473,17 @@
         final AtomicInteger count = this.count;
         if (count.get() == 0)
             return null;
-        E x = null;
-        int c = -1;
+        final E x;
+        final int c;
         final ReentrantLock takeLock = this.takeLock;
         takeLock.lock();
         try {
-            if (count.get() > 0) {
-                x = dequeue();
-                c = count.getAndDecrement();
-                if (c > 1)
-                    notEmpty.signal();
-            }
+            if (count.get() == 0)
+                return null;
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
         } finally {
             takeLock.unlock();
         }
@@ -502,6 +493,7 @@
     }
 
     public E peek() {
+        final AtomicInteger count = this.count;
         if (count.get() == 0)
             return null;
         final ReentrantLock takeLock = this.takeLock;
@@ -514,16 +506,17 @@
     }
 
     /**
-     * Unlinks interior Node p with predecessor trail.
+     * Unlinks interior Node p with predecessor pred.
      */
-    void unlink(Node<E> p, Node<E> trail) {
-        // assert isFullyLocked();
+    void unlink(Node<E> p, Node<E> pred) {
+        // assert putLock.isHeldByCurrentThread();
+        // assert takeLock.isHeldByCurrentThread();
         // p.next is not changed, to allow iterators that are
         // traversing p to maintain their weak-consistency guarantee.
         p.item = null;
-        trail.next = p.next;
+        pred.next = p.next;
         if (last == p)
-            last = trail;
+            last = pred;
         if (count.getAndDecrement() == capacity)
             notFull.signal();
     }
@@ -543,11 +536,11 @@
         if (o == null) return false;
         fullyLock();
         try {
-            for (Node<E> trail = head, p = trail.next;
+            for (Node<E> pred = head, p = pred.next;
                  p != null;
-                 trail = p, p = p.next) {
+                 pred = p, p = p.next) {
                 if (o.equals(p.item)) {
-                    unlink(p, trail);
+                    unlink(p, pred);
                     return true;
                 }
             }
@@ -701,8 +694,7 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        if (c == null)
-            throw new NullPointerException();
+        Objects.requireNonNull(c);
         if (c == this)
             throw new IllegalArgumentException();
         if (maxElements <= 0)
@@ -741,6 +733,18 @@
     }
 
     /**
+     * Used for any element traversal that is not entirely under lock.
+     * Such traversals must handle both:
+     * - dequeued nodes (p.next == p)
+     * - (possibly multiple) interior removed nodes (p.item == null)
+     */
+    Node<E> succ(Node<E> p) {
+        if (p == (p = p.next))
+            p = head.next;
+        return p;
+    }
+
+    /**
      * Returns an iterator over the elements in this queue in proper sequence.
      * The elements will be returned in order from first (head) to last (tail).
      *
@@ -753,71 +757,103 @@
         return new Itr();
     }
 
+    /**
+     * Weakly-consistent iterator.
+     *
+     * Lazily updated ancestor field provides expected O(1) remove(),
+     * but still O(n) in the worst case, whenever the saved ancestor
+     * is concurrently deleted.
+     */
     private class Itr implements Iterator<E> {
-        /*
-         * Basic weakly-consistent iterator.  At all times hold the next
-         * item to hand out so that if hasNext() reports true, we will
-         * still have it to return even if lost race with a take etc.
-         */
-
-        private Node<E> current;
+        private Node<E> next;           // Node holding nextItem
+        private E nextItem;             // next item to hand out
         private Node<E> lastRet;
-        private E currentElement;
+        private Node<E> ancestor;       // Helps unlink lastRet on remove()
 
         Itr() {
             fullyLock();
             try {
-                current = head.next;
-                if (current != null)
-                    currentElement = current.item;
+                if ((next = head.next) != null)
+                    nextItem = next.item;
             } finally {
                 fullyUnlock();
             }
         }
 
         public boolean hasNext() {
-            return current != null;
+            return next != null;
         }
 
         public E next() {
+            Node<E> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            lastRet = p;
+            E x = nextItem;
             fullyLock();
             try {
-                if (current == null)
-                    throw new NoSuchElementException();
-                lastRet = current;
-                E item = null;
-                // Unlike other traversal methods, iterators must handle both:
-                // - dequeued nodes (p.next == p)
-                // - (possibly multiple) interior removed nodes (p.item == null)
-                for (Node<E> p = current, q;; p = q) {
-                    if ((q = p.next) == p)
-                        q = head.next;
-                    if (q == null || (item = q.item) != null) {
-                        current = q;
-                        E x = currentElement;
-                        currentElement = item;
-                        return x;
-                    }
-                }
+                E e = null;
+                for (p = p.next; p != null && (e = p.item) == null; )
+                    p = succ(p);
+                next = p;
+                nextItem = e;
             } finally {
                 fullyUnlock();
             }
+            return x;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            // A variant of forEachFrom
+            Objects.requireNonNull(action);
+            Node<E> p;
+            if ((p = next) == null) return;
+            lastRet = p;
+            next = null;
+            final int batchSize = 64;
+            Object[] es = null;
+            int n, len = 1;
+            do {
+                fullyLock();
+                try {
+                    if (es == null) {
+                        p = p.next;
+                        for (Node<E> q = p; q != null; q = succ(q))
+                            if (q.item != null && ++len == batchSize)
+                                break;
+                        es = new Object[len];
+                        es[0] = nextItem;
+                        nextItem = null;
+                        n = 1;
+                    } else
+                        n = 0;
+                    for (; p != null && n < len; p = succ(p))
+                        if ((es[n] = p.item) != null) {
+                            lastRet = p;
+                            n++;
+                        }
+                } finally {
+                    fullyUnlock();
+                }
+                for (int i = 0; i < n; i++) {
+                    @SuppressWarnings("unchecked") E e = (E) es[i];
+                    action.accept(e);
+                }
+            } while (n > 0 && p != null);
         }
 
         public void remove() {
-            if (lastRet == null)
+            Node<E> p = lastRet;
+            if (p == null)
                 throw new IllegalStateException();
+            lastRet = null;
             fullyLock();
             try {
-                Node<E> node = lastRet;
-                lastRet = null;
-                for (Node<E> trail = head, p = trail.next;
-                     p != null;
-                     trail = p, p = p.next) {
-                    if (p == node) {
-                        unlink(p, trail);
-                        break;
-                    }
+                if (p.item != null) {
+                    if (ancestor == null)
+                        ancestor = head;
+                    ancestor = findPred(p, ancestor);
+                    unlink(p, ancestor);
                 }
             } finally {
                 fullyUnlock();
@@ -825,42 +861,38 @@
         }
     }
 
-    /** A customized variant of Spliterators.IteratorSpliterator */
-    static final class LBQSpliterator<E> implements Spliterator<E> {
+    /**
+     * A customized variant of Spliterators.IteratorSpliterator.
+     * Keep this class in sync with (very similar) LBDSpliterator.
+     */
+    private final class LBQSpliterator implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
-        final LinkedBlockingQueue<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
-        long est;           // size estimate
-        LBQSpliterator(LinkedBlockingQueue<E> queue) {
-            this.queue = queue;
-            this.est = queue.size();
-        }
+        long est = size();  // size estimate
+
+        LBQSpliterator() {}
 
         public long estimateSize() { return est; }
 
         public Spliterator<E> trySplit() {
             Node<E> h;
-            final LinkedBlockingQueue<E> q = this.queue;
-            int b = batch;
-            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
             if (!exhausted &&
-                ((h = current) != null || (h = q.head.next) != null) &&
-                h.next != null) {
+                ((h = current) != null || (h = head.next) != null)
+                && h.next != null) {
+                int n = batch = Math.min(batch + 1, MAX_BATCH);
                 Object[] a = new Object[n];
                 int i = 0;
                 Node<E> p = current;
-                q.fullyLock();
+                fullyLock();
                 try {
-                    if (p != null || (p = q.head.next) != null) {
-                        do {
+                    if (p != null || (p = head.next) != null)
+                        for (; p != null && i < n; p = succ(p))
                             if ((a[i] = p.item) != null)
-                                ++i;
-                        } while ((p = p.next) != null && i < n);
-                    }
+                                i++;
                 } finally {
-                    q.fullyUnlock();
+                    fullyUnlock();
                 }
                 if ((current = p) == null) {
                     est = 0L;
@@ -868,64 +900,32 @@
                 }
                 else if ((est -= i) < 0L)
                     est = 0L;
-                if (i > 0) {
-                    batch = i;
+                if (i > 0)
                     return Spliterators.spliterator
                         (a, 0, i, (Spliterator.ORDERED |
                                    Spliterator.NONNULL |
                                    Spliterator.CONCURRENT));
-                }
             }
             return null;
         }
 
-        public void forEachRemaining(Consumer<? super E> action) {
-            if (action == null) throw new NullPointerException();
-            final LinkedBlockingQueue<E> q = this.queue;
-            if (!exhausted) {
-                exhausted = true;
-                Node<E> p = current;
-                do {
-                    E e = null;
-                    q.fullyLock();
-                    try {
-                        if (p == null)
-                            p = q.head.next;
-                        while (p != null) {
-                            e = p.item;
-                            p = p.next;
-                            if (e != null)
-                                break;
-                        }
-                    } finally {
-                        q.fullyUnlock();
-                    }
-                    if (e != null)
-                        action.accept(e);
-                } while (p != null);
-            }
-        }
-
         public boolean tryAdvance(Consumer<? super E> action) {
-            if (action == null) throw new NullPointerException();
-            final LinkedBlockingQueue<E> q = this.queue;
+            Objects.requireNonNull(action);
             if (!exhausted) {
                 E e = null;
-                q.fullyLock();
+                fullyLock();
                 try {
-                    if (current == null)
-                        current = q.head.next;
-                    while (current != null) {
-                        e = current.item;
-                        current = current.next;
-                        if (e != null)
-                            break;
-                    }
+                    Node<E> p;
+                    if ((p = current) != null || (p = head.next) != null)
+                        do {
+                            e = p.item;
+                            p = succ(p);
+                        } while (e == null && p != null);
+                    if ((current = p) == null)
+                        exhausted = true;
                 } finally {
-                    q.fullyUnlock();
+                    fullyUnlock();
                 }
-                if (current == null)
-                    exhausted = true;
                 if (e != null) {
                     action.accept(e);
                     return true;
@@ -934,9 +934,20 @@
             return false;
         }
 
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                current = null;
+                forEachFrom(action, p);
+            }
+        }
+
         public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.NONNULL |
-                Spliterator.CONCURRENT;
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
         }
     }
 
@@ -957,7 +968,140 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new LBQSpliterator<E>(this);
+        return new LBQSpliterator();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        forEachFrom(action, null);
+    }
+
+    /**
+     * Runs action on each element found during a traversal starting at p.
+     * If p is null, traversal starts at head.
+     */
+    void forEachFrom(Consumer<? super E> action, Node<E> p) {
+        // Extract batches of elements while holding the lock; then
+        // run the action on the elements while not
+        final int batchSize = 64;       // max number of elements per batch
+        Object[] es = null;             // container for batch of elements
+        int n, len = 0;
+        do {
+            fullyLock();
+            try {
+                if (es == null) {
+                    if (p == null) p = head.next;
+                    for (Node<E> q = p; q != null; q = succ(q))
+                        if (q.item != null && ++len == batchSize)
+                            break;
+                    es = new Object[len];
+                }
+                for (n = 0; p != null && n < len; p = succ(p))
+                    if ((es[n] = p.item) != null)
+                        n++;
+            } finally {
+                fullyUnlock();
+            }
+            for (int i = 0; i < n; i++) {
+                @SuppressWarnings("unchecked") E e = (E) es[i];
+                action.accept(e);
+            }
+        } while (n > 0 && p != null);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /**
+     * Returns the predecessor of live node p, given a node that was
+     * once a live ancestor of p (or head); allows unlinking of p.
+     */
+    Node<E> findPred(Node<E> p, Node<E> ancestor) {
+        // assert p.item != null;
+        if (ancestor.item == null)
+            ancestor = head;
+        // Fails with NPE if precondition not satisfied
+        for (Node<E> q; (q = ancestor.next) != p; )
+            ancestor = q;
+        return ancestor;
+    }
+
+    /** Implementation of bulk remove methods. */
+    @SuppressWarnings("unchecked")
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        Node<E> p = null, ancestor = head;
+        Node<E>[] nodes = null;
+        int n, len = 0;
+        do {
+            // 1. Extract batch of up to 64 elements while holding the lock.
+            fullyLock();
+            try {
+                if (nodes == null) {  // first batch; initialize
+                    p = head.next;
+                    for (Node<E> q = p; q != null; q = succ(q))
+                        if (q.item != null && ++len == 64)
+                            break;
+                    nodes = (Node<E>[]) new Node<?>[len];
+                }
+                for (n = 0; p != null && n < len; p = succ(p))
+                    nodes[n++] = p;
+            } finally {
+                fullyUnlock();
+            }
+
+            // 2. Run the filter on the elements while lock is free.
+            long deathRow = 0L;       // "bitset" of size 64
+            for (int i = 0; i < n; i++) {
+                final E e;
+                if ((e = nodes[i].item) != null && filter.test(e))
+                    deathRow |= 1L << i;
+            }
+
+            // 3. Remove any filtered elements while holding the lock.
+            if (deathRow != 0) {
+                fullyLock();
+                try {
+                    for (int i = 0; i < n; i++) {
+                        final Node<E> q;
+                        if ((deathRow & (1L << i)) != 0L
+                            && (q = nodes[i]).item != null) {
+                            ancestor = findPred(q, ancestor);
+                            unlink(q, ancestor);
+                            removed = true;
+                        }
+                        nodes[i] = null; // help GC
+                    }
+                } finally {
+                    fullyUnlock();
+                }
+            }
+        } while (n > 0 && p != null);
+        return removed;
     }
 
     /**
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
index e282b42..06d04e22 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -35,20 +35,20 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Queue;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.concurrent.locks.LockSupport;
 import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
 
 /**
  * An unbounded {@link TransferQueue} based on linked nodes.
@@ -63,16 +63,15 @@
  * asynchronous nature of these queues, determining the current number
  * of elements requires a traversal of the elements, and so may report
  * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code addAll},
- * {@code removeAll}, {@code retainAll}, {@code containsAll},
- * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
- * to be performed atomically. For example, an iterator operating
- * concurrently with an {@code addAll} operation might view only some
- * of the added elements.
  *
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe only some of the added elements.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
  *
  * <p>Memory consistency effects: As with other concurrent
  * collections, actions in a thread prior to placing an object into a
@@ -81,6 +80,10 @@
  * actions subsequent to the access or removal of that element from
  * the {@code LinkedTransferQueue} in another thread.
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @since 1.7
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
@@ -93,8 +96,8 @@
      * *** Overview of Dual Queues with Slack ***
      *
      * Dual Queues, introduced by Scherer and Scott
-     * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are
-     * (linked) queues in which nodes may represent either data or
+     * (http://www.cs.rochester.edu/~scott/papers/2004_DISC_dual_DS.pdf)
+     * are (linked) queues in which nodes may represent either data or
      * requests.  When a thread tries to enqueue a data node, but
      * encounters a request node, it instead "matches" and removes it;
      * and vice versa for enqueuing requests. Blocking Dual Queues
@@ -156,9 +159,8 @@
      * correctly perform enqueue and dequeue operations by traversing
      * from a pointer to the initial node; CASing the item of the
      * first unmatched node on match and CASing the next field of the
-     * trailing node on appends. (Plus some special-casing when
-     * initially empty).  While this would be a terrible idea in
-     * itself, it does have the benefit of not requiring ANY atomic
+     * trailing node on appends.  While this would be a terrible idea
+     * in itself, it does have the benefit of not requiring ANY atomic
      * updates on head/tail fields.
      *
      * We introduce here an approach that lies between the extremes of
@@ -194,15 +196,15 @@
      * with a given probability per traversal step.
      *
      * In any strategy along these lines, because CASes updating
-     * fields may fail, the actual slack may exceed targeted
-     * slack. However, they may be retried at any time to maintain
-     * targets.  Even when using very small slack values, this
-     * approach works well for dual queues because it allows all
-     * operations up to the point of matching or appending an item
-     * (hence potentially allowing progress by another thread) to be
-     * read-only, thus not introducing any further contention. As
-     * described below, we implement this by performing slack
-     * maintenance retries only after these points.
+     * fields may fail, the actual slack may exceed targeted slack.
+     * However, they may be retried at any time to maintain targets.
+     * Even when using very small slack values, this approach works
+     * well for dual queues because it allows all operations up to the
+     * point of matching or appending an item (hence potentially
+     * allowing progress by another thread) to be read-only, thus not
+     * introducing any further contention.  As described below, we
+     * implement this by performing slack maintenance retries only
+     * after these points.
      *
      * As an accompaniment to such techniques, traversal overhead can
      * be further reduced without increasing contention of head
@@ -221,7 +223,7 @@
      * (Similar issues arise in non-GC environments.)  To cope with
      * this in our implementation, upon CASing to advance the head
      * pointer, we set the "next" link of the previous head to point
-     * only to itself; thus limiting the length of connected dead lists.
+     * only to itself; thus limiting the length of chains of dead nodes.
      * (We also take similar care to wipe out possibly garbage
      * retaining values held in other Node fields.)  However, doing so
      * adds some further complexity to traversal: If any "next"
@@ -264,15 +266,6 @@
      * interior nodes) except in the case of cancellation/removal (see
      * below).
      *
-     * We allow both the head and tail fields to be null before any
-     * nodes are enqueued; initializing upon first append.  This
-     * simplifies some other logic, as well as providing more
-     * efficient explicit control paths instead of letting JVMs insert
-     * implicit NullPointerExceptions when they are null.  While not
-     * currently fully implemented, we also leave open the possibility
-     * of re-nulling these fields when empty (which is complicated to
-     * arrange, for little benefit.)
-     *
      * All enqueue/dequeue operations are handled by the single method
      * "xfer" with parameters indicating whether to act as some form
      * of offer, put, poll, take, or transfer (each possibly with
@@ -280,44 +273,40 @@
      * method outweighs the code bulk and maintenance problems of
      * using separate methods for each case.
      *
-     * Operation consists of up to three phases. The first is
-     * implemented within method xfer, the second in tryAppend, and
-     * the third in method awaitMatch.
+     * Operation consists of up to two phases. The first is implemented
+     * in method xfer, the second in method awaitMatch.
      *
-     * 1. Try to match an existing node
+     * 1. Traverse until matching or appending (method xfer)
      *
-     *    Starting at head, skip already-matched nodes until finding
-     *    an unmatched node of opposite mode, if one exists, in which
-     *    case matching it and returning, also if necessary updating
-     *    head to one past the matched node (or the node itself if the
-     *    list has no other unmatched nodes). If the CAS misses, then
-     *    a loop retries advancing head by two steps until either
-     *    success or the slack is at most two. By requiring that each
-     *    attempt advances head by two (if applicable), we ensure that
-     *    the slack does not grow without bound. Traversals also check
-     *    if the initial head is now off-list, in which case they
-     *    start at the new head.
+     *    Conceptually, we simply traverse all nodes starting from head.
+     *    If we encounter an unmatched node of opposite mode, we match
+     *    it and return, also updating head (by at least 2 hops) to
+     *    one past the matched node (or the node itself if it's the
+     *    pinned trailing node).  Traversals also check for the
+     *    possibility of falling off-list, in which case they restart.
      *
-     *    If no candidates are found and the call was untimed
-     *    poll/offer, (argument "how" is NOW) return.
+     *    If the trailing node of the list is reached, a match is not
+     *    possible.  If this call was untimed poll or tryTransfer
+     *    (argument "how" is NOW), return empty-handed immediately.
+     *    Else a new node is CAS-appended.  On successful append, if
+     *    this call was ASYNC (e.g. offer), an element was
+     *    successfully added to the end of the queue and we return.
      *
-     * 2. Try to append a new node (method tryAppend)
+     *    Of course, this naive traversal is O(n) when no match is
+     *    possible.  We optimize the traversal by maintaining a tail
+     *    pointer, which is expected to be "near" the end of the list.
+     *    It is only safe to fast-forward to tail (in the presence of
+     *    arbitrary concurrent changes) if it is pointing to a node of
+     *    the same mode, even if it is dead (in this case no preceding
+     *    node could still be matchable by this traversal).  If we
+     *    need to restart due to falling off-list, we can again
+     *    fast-forward to tail, but only if it has changed since the
+     *    last traversal (else we might loop forever).  If tail cannot
+     *    be used, traversal starts at head (but in this case we
+     *    expect to be able to match near head).  As with head, we
+     *    CAS-advance the tail pointer by at least two hops.
      *
-     *    Starting at current tail pointer, find the actual last node
-     *    and try to append a new node (or if head was null, establish
-     *    the first node). Nodes can be appended only if their
-     *    predecessors are either already matched or are of the same
-     *    mode. If we detect otherwise, then a new node with opposite
-     *    mode must have been appended during traversal, so we must
-     *    restart at phase 1. The traversal and update steps are
-     *    otherwise similar to phase 1: Retrying upon CAS misses and
-     *    checking for staleness.  In particular, if a self-link is
-     *    encountered, then we can safely jump to a node on the list
-     *    by continuing the traversal at current head.
-     *
-     *    On successful append, if the call was ASYNC, return.
-     *
-     * 3. Await match or cancellation (method awaitMatch)
+     * 2. Await match or cancellation (method awaitMatch)
      *
      *    Wait for another thread to match node; instead cancelling if
      *    the current thread was interrupted or the wait timed out. On
@@ -371,12 +360,12 @@
      * from, the head of list.
      *
      * Without taking these into account, it would be possible for an
-     * unbounded number of supposedly removed nodes to remain
-     * reachable.  Situations leading to such buildup are uncommon but
-     * can occur in practice; for example when a series of short timed
-     * calls to poll repeatedly time out but never otherwise fall off
-     * the list because of an untimed call to take at the front of the
-     * queue.
+     * unbounded number of supposedly removed nodes to remain reachable.
+     * Situations leading to such buildup are uncommon but can occur
+     * in practice; for example when a series of short timed calls to
+     * poll repeatedly time out at the trailing node but otherwise
+     * never fall off the list because of an untimed call to take() at
+     * the front of the queue.
      *
      * When these cases arise, rather than always retraversing the
      * entire list to find an actual predecessor to unlink (which
@@ -389,10 +378,9 @@
      * We perform sweeps by the thread hitting threshold (rather than
      * background threads or by spreading work to other threads)
      * because in the main contexts in which removal occurs, the
-     * caller is already timed-out, cancelled, or performing a
-     * potentially O(n) operation (e.g. remove(x)), none of which are
-     * time-critical enough to warrant the overhead that alternatives
-     * would impose on other threads.
+     * caller is timed-out or cancelled, which are not time-critical
+     * enough to warrant the overhead that alternatives would impose
+     * on other threads.
      *
      * Because the sweepVotes estimate is conservative, and because
      * nodes become unlinked "naturally" as they fall off the head of
@@ -404,6 +392,13 @@
      * quiescent queues. The value defined below was chosen
      * empirically to balance these under various timeout scenarios.
      *
+     * Because traversal operations on the linked list of nodes are a
+     * natural opportunity to sweep dead nodes, we generally do so,
+     * including all the operations that might remove elements as they
+     * traverse, such as removeIf and Iterator.remove.  This largely
+     * eliminates long chains of dead interior nodes, except from
+     * cancelled or timed out blocking operations.
+     *
      * Note that we cannot self-link unlinked interior nodes during
      * sweeps. However, the associated garbage chains terminate when
      * some successor ultimately falls off the head of the list and is
@@ -444,55 +439,72 @@
 
     /**
      * Queue nodes. Uses Object, not E, for items to allow forgetting
-     * them after use.  Relies heavily on Unsafe mechanics to minimize
-     * unnecessary ordering constraints: Writes that are intrinsically
-     * ordered wrt other accesses or CASes use simple relaxed forms.
+     * them after use.  Writes that are intrinsically ordered wrt
+     * other accesses or CASes use simple relaxed forms.
      */
     static final class Node {
         final boolean isData;   // false if this is a request node
         volatile Object item;   // initially non-null if isData; CASed to match
         volatile Node next;
-        volatile Thread waiter; // null until waiting
+        volatile Thread waiter; // null when not waiting for a match
 
-        // CAS methods for fields
+        /**
+         * Constructs a data node holding item if item is non-null,
+         * else a request node.  Uses relaxed write because item can
+         * only be seen after piggy-backing publication via CAS.
+         */
+        Node(Object item) {
+            ITEM.set(this, item);
+            isData = (item != null);
+        }
+
+        /** Constructs a (matched data) dummy node. */
+        Node() {
+            isData = true;
+        }
+
         final boolean casNext(Node cmp, Node val) {
-            return U.compareAndSwapObject(this, NEXT, cmp, val);
+            // assert val != null;
+            return NEXT.compareAndSet(this, cmp, val);
         }
 
         final boolean casItem(Object cmp, Object val) {
-            // assert cmp == null || cmp.getClass() != Node.class;
-            return U.compareAndSwapObject(this, ITEM, cmp, val);
-        }
-
-        /**
-         * Constructs a new node.  Uses relaxed write because item can
-         * only be seen after publication via casNext.
-         */
-        Node(Object item, boolean isData) {
-            U.putObject(this, ITEM, item); // relaxed write
-            this.isData = isData;
+            // assert isData == (cmp != null);
+            // assert isData == (val == null);
+            // assert !(cmp instanceof Node);
+            return ITEM.compareAndSet(this, cmp, val);
         }
 
         /**
          * Links node to itself to avoid garbage retention.  Called
          * only after CASing head field, so uses relaxed write.
          */
-        final void forgetNext() {
-            U.putObject(this, NEXT, this);
+        final void selfLink() {
+            // assert isMatched();
+            NEXT.setRelease(this, this);
+        }
+
+        final void appendRelaxed(Node next) {
+            // assert next != null;
+            // assert this.next == null;
+            NEXT.set(this, next);
         }
 
         /**
-         * Sets item to self and waiter to null, to avoid garbage
-         * retention after matching or cancelling. Uses relaxed writes
-         * because order is already constrained in the only calling
-         * contexts: item is forgotten only after volatile/atomic
-         * mechanics that extract items.  Similarly, clearing waiter
-         * follows either CAS or return from park (if ever parked;
-         * else we don't care).
+         * Sets item (of a request node) to self and waiter to null,
+         * to avoid garbage retention after matching or cancelling.
+         * Uses relaxed writes because order is already constrained in
+         * the only calling contexts: item is forgotten only after
+         * volatile/atomic mechanics that extract items, and visitors
+         * of request nodes only ever check whether item is null.
+         * Similarly, clearing waiter follows either CAS or return
+         * from park (if ever parked; else we don't care).
          */
         final void forgetContents() {
-            U.putObject(this, ITEM, this);
-            U.putObject(this, WAITER, null);
+            // assert isMatched();
+            if (!isData)
+                ITEM.set(this, this);
+            WAITER.set(this, null);
         }
 
         /**
@@ -500,15 +512,16 @@
          * case of artificial matches due to cancellation.
          */
         final boolean isMatched() {
-            Object x = item;
-            return (x == this) || ((x == null) == isData);
+            return isData == (item == null);
         }
 
-        /**
-         * Returns true if this is an unmatched request node.
-         */
-        final boolean isUnmatchedRequest() {
-            return !isData && item == null;
+        /** Tries to CAS-match this node; if successful, wakes waiter. */
+        final boolean tryMatch(Object cmp, Object val) {
+            if (casItem(cmp, val)) {
+                LockSupport.unpark(waiter);
+                return true;
+            }
+            return false;
         }
 
         /**
@@ -518,69 +531,118 @@
          */
         final boolean cannotPrecede(boolean haveData) {
             boolean d = isData;
-            Object x;
-            return d != haveData && (x = item) != this && (x != null) == d;
-        }
-
-        /**
-         * Tries to artificially match a data node -- used by remove.
-         */
-        final boolean tryMatchData() {
-            // assert isData;
-            Object x = item;
-            if (x != null && x != this && casItem(x, null)) {
-                LockSupport.unpark(waiter);
-                return true;
-            }
-            return false;
+            return d != haveData && d != (item == null);
         }
 
         private static final long serialVersionUID = -3375979862319811754L;
-
-        // Unsafe mechanics
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-        private static final long ITEM;
-        private static final long NEXT;
-        private static final long WAITER;
-        static {
-            try {
-                ITEM = U.objectFieldOffset
-                    (Node.class.getDeclaredField("item"));
-                NEXT = U.objectFieldOffset
-                    (Node.class.getDeclaredField("next"));
-                WAITER = U.objectFieldOffset
-                    (Node.class.getDeclaredField("waiter"));
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-        }
     }
 
-    /** head of the queue; null until first enqueue */
+    /**
+     * A node from which the first live (non-matched) node (if any)
+     * can be reached in O(1) time.
+     * Invariants:
+     * - all live nodes are reachable from head via .next
+     * - head != null
+     * - (tmp = head).next != tmp || tmp != head
+     * Non-invariants:
+     * - head may or may not be live
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     */
     transient volatile Node head;
 
-    /** tail of the queue; null until first append */
+    /**
+     * A node from which the last node on list (that is, the unique
+     * node with node.next == null) can be reached in O(1) time.
+     * Invariants:
+     * - the last node is always reachable from tail via .next
+     * - tail != null
+     * Non-invariants:
+     * - tail may or may not be live
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     * - tail.next may or may not be self-linked.
+     */
     private transient volatile Node tail;
 
-    /** The number of apparent failures to unsplice removed nodes */
+    /** The number of apparent failures to unsplice cancelled nodes */
     private transient volatile int sweepVotes;
 
-    // CAS methods for fields
     private boolean casTail(Node cmp, Node val) {
-        return U.compareAndSwapObject(this, TAIL, cmp, val);
+        // assert cmp != null;
+        // assert val != null;
+        return TAIL.compareAndSet(this, cmp, val);
     }
 
     private boolean casHead(Node cmp, Node val) {
-        return U.compareAndSwapObject(this, HEAD, cmp, val);
+        return HEAD.compareAndSet(this, cmp, val);
     }
 
-    private boolean casSweepVotes(int cmp, int val) {
-        return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
+    /** Atomic version of ++sweepVotes. */
+    private int incSweepVotes() {
+        return (int) SWEEPVOTES.getAndAdd(this, 1) + 1;
     }
 
-    /*
-     * Possible values for "how" argument in xfer method.
+    /**
+     * Tries to CAS pred.next (or head, if pred is null) from c to p.
+     * Caller must ensure that we're not unlinking the trailing node.
      */
+    private boolean tryCasSuccessor(Node pred, Node c, Node p) {
+        // assert p != null;
+        // assert c.isData != (c.item != null);
+        // assert c != p;
+        if (pred != null)
+            return pred.casNext(c, p);
+        if (casHead(c, p)) {
+            c.selfLink();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Collapses dead (matched) nodes between pred and q.
+     * @param pred the last known live node, or null if none
+     * @param c the first dead node
+     * @param p the last dead node
+     * @param q p.next: the next live node, or null if at end
+     * @return pred if pred still alive and CAS succeeded; else p
+     */
+    private Node skipDeadNodes(Node pred, Node c, Node p, Node q) {
+        // assert pred != c;
+        // assert p != q;
+        // assert c.isMatched();
+        // assert p.isMatched();
+        if (q == null) {
+            // Never unlink trailing node.
+            if (c == p) return pred;
+            q = p;
+        }
+        return (tryCasSuccessor(pred, c, q)
+                && (pred == null || !pred.isMatched()))
+            ? pred : p;
+    }
+
+    /**
+     * Collapses dead (matched) nodes from h (which was once head) to p.
+     * Caller ensures all nodes from h up to and including p are dead.
+     */
+    private void skipDeadNodesNearHead(Node h, Node p) {
+        // assert h != null;
+        // assert h != p;
+        // assert p.isMatched();
+        for (;;) {
+            final Node q;
+            if ((q = p.next) == null) break;
+            else if (!q.isMatched()) { p = q; break; }
+            else if (p == (p = q)) return;
+        }
+        if (casHead(h, p))
+            h.selfLink();
+    }
+
+    /* Possible values for "how" argument in xfer method. */
+
     private static final int NOW   = 0; // for untimed poll, tryTransfer
     private static final int ASYNC = 1; // for offer, put, add
     private static final int SYNC  = 2; // for transfer, take
@@ -596,84 +658,32 @@
      * @return an item if matched, else e
      * @throws NullPointerException if haveData mode but e is null
      */
+    @SuppressWarnings("unchecked")
     private E xfer(E e, boolean haveData, int how, long nanos) {
         if (haveData && (e == null))
             throw new NullPointerException();
-        Node s = null;                        // the node to append, if needed
 
-        retry:
-        for (;;) {                            // restart on append race
-
-            for (Node h = head, p = h; p != null;) { // find & match first node
-                boolean isData = p.isData;
-                Object item = p.item;
-                if (item != p && (item != null) == isData) { // unmatched
-                    if (isData == haveData)   // can't match
-                        break;
-                    if (p.casItem(item, e)) { // match
-                        for (Node q = p; q != h;) {
-                            Node n = q.next;  // update by 2 unless singleton
-                            if (head == h && casHead(h, n == null ? q : n)) {
-                                h.forgetNext();
-                                break;
-                            }                 // advance and retry
-                            if ((h = head)   == null ||
-                                (q = h.next) == null || !q.isMatched())
-                                break;        // unless slack < 2
-                        }
-                        LockSupport.unpark(p.waiter);
-                        @SuppressWarnings("unchecked") E itemE = (E) item;
-                        return itemE;
+        restart: for (Node s = null, t = null, h = null;;) {
+            for (Node p = (t != (t = tail) && t.isData == haveData) ? t
+                     : (h = head);; ) {
+                final Node q; final Object item;
+                if (p.isData != haveData
+                    && haveData == ((item = p.item) == null)) {
+                    if (h == null) h = head;
+                    if (p.tryMatch(item, e)) {
+                        if (h != p) skipDeadNodesNearHead(h, p);
+                        return (E) item;
                     }
                 }
-                Node n = p.next;
-                p = (p != n) ? n : (h = head); // Use head if p offlist
-            }
-
-            if (how != NOW) {                 // No matches available
-                if (s == null)
-                    s = new Node(e, haveData);
-                Node pred = tryAppend(s, haveData);
-                if (pred == null)
-                    continue retry;           // lost race vs opposite mode
-                if (how != ASYNC)
-                    return awaitMatch(s, pred, e, (how == TIMED), nanos);
-            }
-            return e; // not waiting
-        }
-    }
-
-    /**
-     * Tries to append node s as tail.
-     *
-     * @param s the node to append
-     * @param haveData true if appending in data mode
-     * @return null on failure due to losing race with append in
-     * different mode, else s's predecessor, or s itself if no
-     * predecessor
-     */
-    private Node tryAppend(Node s, boolean haveData) {
-        for (Node t = tail, p = t;;) {        // move p to last node and append
-            Node n, u;                        // temps for reads of next & tail
-            if (p == null && (p = head) == null) {
-                if (casHead(null, s))
-                    return s;                 // initialize
-            }
-            else if (p.cannotPrecede(haveData))
-                return null;                  // lost race vs opposite mode
-            else if ((n = p.next) != null)    // not last; keep traversing
-                p = p != t && t != (u = tail) ? (t = u) : // stale tail
-                    (p != n) ? n : null;      // restart if off list
-            else if (!p.casNext(null, s))
-                p = p.next;                   // re-read on CAS failure
-            else {
-                if (p != t) {                 // update if slack now >= 2
-                    while ((tail != t || !casTail(t, s)) &&
-                           (t = tail)   != null &&
-                           (s = t.next) != null && // advance and retry
-                           (s = s.next) != null && s != t);
+                if ((q = p.next) == null) {
+                    if (how == NOW) return e;
+                    if (s == null) s = new Node(e);
+                    if (!p.casNext(null, s)) continue;
+                    if (p != t) casTail(t, s);
+                    if (how == ASYNC) return e;
+                    return awaitMatch(s, p, e, (how == TIMED), nanos);
                 }
-                return p;
+                if (p == (p = q)) continue restart;
             }
         }
     }
@@ -682,9 +692,9 @@
      * Spins/yields/blocks until node s is matched or caller gives up.
      *
      * @param s the waiting node
-     * @param pred the predecessor of s, or s itself if it has no
-     * predecessor, or null if unknown (the null case does not occur
-     * in any current calls but may in possible future extensions)
+     * @param pred the predecessor of s, or null if unknown (the null
+     * case does not occur in any current calls but may in possible
+     * future extensions)
      * @param e the comparison value for checking match
      * @param timed if true, wait only until timeout elapses
      * @param nanos timeout in nanosecs, used only if timed is true
@@ -697,17 +707,20 @@
         ThreadLocalRandom randomYields = null; // bound if needed
 
         for (;;) {
-            Object item = s.item;
-            if (item != e) {                  // matched
+            final Object item;
+            if ((item = s.item) != e) {       // matched
                 // assert item != s;
                 s.forgetContents();           // avoid garbage
                 @SuppressWarnings("unchecked") E itemE = (E) item;
                 return itemE;
             }
             else if (w.isInterrupted() || (timed && nanos <= 0L)) {
-                unsplice(pred, s);           // try to unlink and cancel
-                if (s.casItem(e, s))         // return normally if lost CAS
+                // try to cancel and unlink
+                if (s.casItem(e, s.isData ? null : s)) {
+                    unsplice(pred, s);
                     return e;
+                }
+                // return normally if lost CAS
             }
             else if (spins < 0) {            // establish spins at/near front
                 if ((spins = spinsFor(pred, s.isData)) > 0)
@@ -751,34 +764,32 @@
     /* -------------- Traversal methods -------------- */
 
     /**
-     * Returns the successor of p, or the head node if p.next has been
-     * linked to self, which will only be true if traversing with a
-     * stale pointer that is now off the list.
-     */
-    final Node succ(Node p) {
-        Node next = p.next;
-        return (p == next) ? head : next;
-    }
-
-    /**
      * Returns the first unmatched data node, or null if none.
-     * Callers must recheck if the returned node's item field is null
-     * or self-linked before using.
+     * Callers must recheck if the returned node is unmatched
+     * before using.
      */
     final Node firstDataNode() {
+        Node first = null;
         restartFromHead: for (;;) {
-            for (Node p = head; p != null;) {
-                Object item = p.item;
-                if (p.isData) {
-                    if (item != null && item != p)
-                        return p;
+            Node h = head, p = h;
+            while (p != null) {
+                if (p.item != null) {
+                    if (p.isData) {
+                        first = p;
+                        break;
+                    }
                 }
-                else if (item == null)
+                else if (!p.isData)
                     break;
-                if (p == (p = p.next))
+                final Node q;
+                if ((q = p.next) == null)
+                    break;
+                if (p == (p = q))
                     continue restartFromHead;
             }
-            return null;
+            if (p != h && casHead(h, p))
+                h.selfLink();
+            return first;
         }
     }
 
@@ -811,7 +822,7 @@
             for (Node p = head; p != null;) {
                 Object item = p.item;
                 if (p.isData) {
-                    if (item != null && item != p) {
+                    if (item != null) {
                         if (a == null)
                             a = new String[4];
                         else if (size == a.length)
@@ -840,7 +851,7 @@
             for (Node p = head; p != null;) {
                 Object item = p.item;
                 if (p.isData) {
-                    if (item != null && item != p) {
+                    if (item != null) {
                         if (x == null)
                             x = new Object[4];
                         else if (size == x.length)
@@ -919,76 +930,50 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        if (a == null) throw new NullPointerException();
+        Objects.requireNonNull(a);
         return (T[]) toArrayInternal(a);
     }
 
+    /**
+     * Weakly-consistent iterator.
+     *
+     * Lazily updated ancestor is expected to be amortized O(1) remove(),
+     * but O(n) in the worst case, when lastRet is concurrently deleted.
+     */
     final class Itr implements Iterator<E> {
         private Node nextNode;   // next node to return item for
         private E nextItem;      // the corresponding item
         private Node lastRet;    // last returned node, to support remove
-        private Node lastPred;   // predecessor to unlink lastRet
+        private Node ancestor;   // Helps unlink lastRet on remove()
 
         /**
-         * Moves to next node after prev, or first node if prev null.
+         * Moves to next node after pred, or first node if pred null.
          */
-        private void advance(Node prev) {
-            /*
-             * To track and avoid buildup of deleted nodes in the face
-             * of calls to both Queue.remove and Itr.remove, we must
-             * include variants of unsplice and sweep upon each
-             * advance: Upon Itr.remove, we may need to catch up links
-             * from lastPred, and upon other removes, we might need to
-             * skip ahead from stale nodes and unsplice deleted ones
-             * found while advancing.
-             */
-
-            Node r, b; // reset lastPred upon possible deletion of lastRet
-            if ((r = lastRet) != null && !r.isMatched())
-                lastPred = r;    // next lastPred is old lastRet
-            else if ((b = lastPred) == null || b.isMatched())
-                lastPred = null; // at start of list
-            else {
-                Node s, n;       // help with removal of lastPred.next
-                while ((s = b.next) != null &&
-                       s != b && s.isMatched() &&
-                       (n = s.next) != null && n != s)
-                    b.casNext(s, n);
-            }
-
-            this.lastRet = prev;
-
-            for (Node p = prev, s, n;;) {
-                s = (p == null) ? head : p.next;
-                if (s == null)
-                    break;
-                else if (s == p) {
-                    p = null;
-                    continue;
+        @SuppressWarnings("unchecked")
+        private void advance(Node pred) {
+            for (Node p = (pred == null) ? head : pred.next, c = p;
+                 p != null; ) {
+                final Object item;
+                if ((item = p.item) != null && p.isData) {
+                    nextNode = p;
+                    nextItem = (E) item;
+                    if (c != p)
+                        tryCasSuccessor(pred, c, p);
+                    return;
                 }
-                Object item = s.item;
-                if (s.isData) {
-                    if (item != null && item != s) {
-                        @SuppressWarnings("unchecked") E itemE = (E) item;
-                        nextItem = itemE;
-                        nextNode = s;
-                        return;
-                    }
+                else if (!p.isData && item == null)
+                    break;
+                if (c != p && !tryCasSuccessor(pred, c, c = p)) {
+                    pred = p;
+                    c = p = p.next;
                 }
-                else if (item == null)
-                    break;
-                // assert s.isMatched();
-                if (p == null)
-                    p = s;
-                else if ((n = s.next) == null)
-                    break;
-                else if (s == n)
-                    p = null;
-                else
-                    p.casNext(s, n);
+                else if (p == (p = p.next)) {
+                    pred = null;
+                    c = p = head;
+                }
             }
-            nextNode = null;
             nextItem = null;
+            nextNode = null;
         }
 
         Itr() {
@@ -1000,25 +985,67 @@
         }
 
         public final E next() {
-            Node p = nextNode;
-            if (p == null) throw new NoSuchElementException();
+            final Node p;
+            if ((p = nextNode) == null) throw new NoSuchElementException();
             E e = nextItem;
-            advance(p);
+            advance(lastRet = p);
             return e;
         }
 
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            Node q = null;
+            for (Node p; (p = nextNode) != null; advance(q = p))
+                action.accept(nextItem);
+            if (q != null)
+                lastRet = q;
+        }
+
         public final void remove() {
             final Node lastRet = this.lastRet;
             if (lastRet == null)
                 throw new IllegalStateException();
             this.lastRet = null;
-            if (lastRet.tryMatchData())
-                unsplice(lastPred, lastRet);
+            if (lastRet.item == null)   // already deleted?
+                return;
+            // Advance ancestor, collapsing intervening dead nodes
+            Node pred = ancestor;
+            for (Node p = (pred == null) ? head : pred.next, c = p, q;
+                 p != null; ) {
+                if (p == lastRet) {
+                    final Object item;
+                    if ((item = p.item) != null)
+                        p.tryMatch(item, null);
+                    if ((q = p.next) == null) q = p;
+                    if (c != q) tryCasSuccessor(pred, c, q);
+                    ancestor = pred;
+                    return;
+                }
+                final Object item; final boolean pAlive;
+                if (pAlive = ((item = p.item) != null && p.isData)) {
+                    // exceptionally, nothing to do
+                }
+                else if (!p.isData && item == null)
+                    break;
+                if ((c != p && !tryCasSuccessor(pred, c, c = p)) || pAlive) {
+                    pred = p;
+                    c = p = p.next;
+                }
+                else if (p == (p = p.next)) {
+                    pred = null;
+                    c = p = head;
+                }
+            }
+            // traversal failed to find lastRet; must have been deleted;
+            // leave ancestor at original location to avoid overshoot;
+            // better luck next time!
+
+            // assert lastRet.isMatched();
         }
     }
 
     /** A customized variant of Spliterators.IteratorSpliterator */
-    final class LTQSpliterator<E> implements Spliterator<E> {
+    final class LTQSpliterator implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
         Node current;       // current node; null until initialized
         int batch;          // batch size for splits
@@ -1026,79 +1053,90 @@
         LTQSpliterator() {}
 
         public Spliterator<E> trySplit() {
-            Node p;
-            int b = batch;
-            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
-            if (!exhausted &&
-                ((p = current) != null || (p = firstDataNode()) != null) &&
-                p.next != null) {
-                Object[] a = new Object[n];
-                int i = 0;
-                do {
-                    Object e = p.item;
-                    if (e != p && (a[i] = e) != null)
-                        ++i;
-                    if (p == (p = p.next))
-                        p = firstDataNode();
-                } while (p != null && i < n && p.isData);
-                if ((current = p) == null)
-                    exhausted = true;
-                if (i > 0) {
-                    batch = i;
-                    return Spliterators.spliterator
-                        (a, 0, i, (Spliterator.ORDERED |
-                                   Spliterator.NONNULL |
-                                   Spliterator.CONCURRENT));
+            Node p, q;
+            if ((p = current()) == null || (q = p.next) == null)
+                return null;
+            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+            Object[] a = null;
+            do {
+                final Object item = p.item;
+                if (p.isData) {
+                    if (item != null) {
+                        if (a == null)
+                            a = new Object[n];
+                        a[i++] = item;
+                    }
+                } else if (item == null) {
+                    p = null;
+                    break;
                 }
-            }
-            return null;
+                if (p == (p = q))
+                    p = firstDataNode();
+            } while (p != null && (q = p.next) != null && i < n);
+            setCurrent(p);
+            return (i == 0) ? null :
+                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+                                                   Spliterator.NONNULL |
+                                                   Spliterator.CONCURRENT));
         }
 
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
-            Node p;
-            if (action == null) throw new NullPointerException();
-            if (!exhausted &&
-                ((p = current) != null || (p = firstDataNode()) != null)) {
+            Objects.requireNonNull(action);
+            final Node p;
+            if ((p = current()) != null) {
+                current = null;
                 exhausted = true;
-                do {
-                    Object e = p.item;
-                    if (e != null && e != p)
-                        action.accept((E)e);
-                    if (p == (p = p.next))
-                        p = firstDataNode();
-                } while (p != null && p.isData);
+                forEachFrom(action, p);
             }
         }
 
         @SuppressWarnings("unchecked")
         public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
             Node p;
-            if (action == null) throw new NullPointerException();
-            if (!exhausted &&
-                ((p = current) != null || (p = firstDataNode()) != null)) {
-                Object e;
+            if ((p = current()) != null) {
+                E e = null;
                 do {
-                    if ((e = p.item) == p)
-                        e = null;
+                    final Object item = p.item;
+                    final boolean isData = p.isData;
                     if (p == (p = p.next))
-                        p = firstDataNode();
-                } while (e == null && p != null && p.isData);
-                if ((current = p) == null)
-                    exhausted = true;
+                        p = head;
+                    if (isData) {
+                        if (item != null) {
+                            e = (E) item;
+                            break;
+                        }
+                    }
+                    else if (item == null)
+                        p = null;
+                } while (p != null);
+                setCurrent(p);
                 if (e != null) {
-                    action.accept((E)e);
+                    action.accept(e);
                     return true;
                 }
             }
             return false;
         }
 
+        private void setCurrent(Node p) {
+            if ((current = p) == null)
+                exhausted = true;
+        }
+
+        private Node current() {
+            Node p;
+            if ((p = current) == null && !exhausted)
+                setCurrent(p = firstDataNode());
+            return p;
+        }
+
         public long estimateSize() { return Long.MAX_VALUE; }
 
         public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.NONNULL |
-                Spliterator.CONCURRENT;
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
         }
     }
 
@@ -1119,7 +1157,7 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new LTQSpliterator<E>();
+        return new LTQSpliterator();
     }
 
     /* -------------- Removal methods -------------- */
@@ -1129,10 +1167,15 @@
      * the given predecessor.
      *
      * @param pred a node that was at one time known to be the
-     * predecessor of s, or null or s itself if s is/was at head
+     * predecessor of s
      * @param s the node to be unspliced
      */
     final void unsplice(Node pred, Node s) {
+        // assert pred != null;
+        // assert pred != s;
+        // assert s != null;
+        // assert s.isMatched();
+        // assert (SWEEP_THRESHOLD & (SWEEP_THRESHOLD - 1)) == 0;
         s.waiter = null; // disable signals
         /*
          * See above for rationale. Briefly: if pred still points to
@@ -1141,13 +1184,13 @@
          * nor s are head or offlist, add to sweepVotes, and if enough
          * votes have accumulated, sweep.
          */
-        if (pred != null && pred != s && pred.next == s) {
+        if (pred != null && pred.next == s) {
             Node n = s.next;
             if (n == null ||
                 (n != s && pred.casNext(s, n) && pred.isMatched())) {
                 for (;;) {               // check if at, or could be, head
                     Node h = head;
-                    if (h == pred || h == s || h == null)
+                    if (h == pred || h == s)
                         return;          // at head or list empty
                     if (!h.isMatched())
                         break;
@@ -1155,21 +1198,12 @@
                     if (hn == null)
                         return;          // now empty
                     if (hn != h && casHead(h, hn))
-                        h.forgetNext();  // advance head
+                        h.selfLink();  // advance head
                 }
-                if (pred.next != pred && s.next != s) { // recheck if offlist
-                    for (;;) {           // sweep now if enough votes
-                        int v = sweepVotes;
-                        if (v < SWEEP_THRESHOLD) {
-                            if (casSweepVotes(v, v + 1))
-                                break;
-                        }
-                        else if (casSweepVotes(v, 0)) {
-                            sweep();
-                            break;
-                        }
-                    }
-                }
+                // sweep every SWEEP_THRESHOLD votes
+                if (pred.next != pred && s.next != s // recheck if offlist
+                    && (incSweepVotes() & (SWEEP_THRESHOLD - 1)) == 0)
+                    sweep();
             }
         }
     }
@@ -1194,35 +1228,10 @@
     }
 
     /**
-     * Main implementation of remove(Object)
-     */
-    private boolean findAndRemove(Object e) {
-        if (e != null) {
-            for (Node pred = null, p = head; p != null; ) {
-                Object item = p.item;
-                if (p.isData) {
-                    if (item != null && item != p && e.equals(item) &&
-                        p.tryMatchData()) {
-                        unsplice(pred, p);
-                        return true;
-                    }
-                }
-                else if (item == null)
-                    break;
-                pred = p;
-                if ((p = p.next) == pred) { // stale
-                    pred = null;
-                    p = head;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
      * Creates an initially empty {@code LinkedTransferQueue}.
      */
     public LinkedTransferQueue() {
+        head = tail = new Node();
     }
 
     /**
@@ -1235,8 +1244,18 @@
      *         of its elements are null
      */
     public LinkedTransferQueue(Collection<? extends E> c) {
-        this();
-        addAll(c);
+        Node h = null, t = null;
+        for (E e : c) {
+            Node newNode = new Node(Objects.requireNonNull(e));
+            if (h == null)
+                h = t = newNode;
+            else
+                t.appendRelaxed(t = newNode);
+        }
+        if (h == null)
+            h = t = new Node();
+        head = h;
+        tail = t;
     }
 
     /**
@@ -1255,8 +1274,7 @@
      * return {@code false}.
      *
      * @return {@code true} (as specified by
-     *  {@link java.util.concurrent.BlockingQueue#offer(Object,long,TimeUnit)
-     *  BlockingQueue.offer})
+     *  {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer})
      * @throws NullPointerException if the specified element is null
      */
     public boolean offer(E e, long timeout, TimeUnit unit) {
@@ -1368,15 +1386,12 @@
      * @throws IllegalArgumentException {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c) {
-        if (c == null)
-            throw new NullPointerException();
+        Objects.requireNonNull(c);
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        for (E e; (e = poll()) != null;) {
+        for (E e; (e = poll()) != null; n++)
             c.add(e);
-            ++n;
-        }
         return n;
     }
 
@@ -1385,15 +1400,12 @@
      * @throws IllegalArgumentException {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        if (c == null)
-            throw new NullPointerException();
+        Objects.requireNonNull(c);
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        for (E e; n < maxElements && (e = poll()) != null;) {
+        for (E e; n < maxElements && (e = poll()) != null; n++)
             c.add(e);
-            ++n;
-        }
         return n;
     }
 
@@ -1415,7 +1427,7 @@
             for (Node p = head; p != null;) {
                 Object item = p.item;
                 if (p.isData) {
-                    if (item != null && item != p) {
+                    if (item != null) {
                         @SuppressWarnings("unchecked") E e = (E) item;
                         return e;
                     }
@@ -1443,7 +1455,7 @@
             for (Node p = head; p != null;) {
                 Object item = p.item;
                 if (p.isData) {
-                    if (item != null && item != p)
+                    if (item != null)
                         break;
                 }
                 else if (item == null)
@@ -1487,7 +1499,31 @@
      * @return {@code true} if this queue changed as a result of the call
      */
     public boolean remove(Object o) {
-        return findAndRemove(o);
+        if (o == null) return false;
+        restartFromHead: for (;;) {
+            for (Node p = head, pred = null; p != null; ) {
+                Node q = p.next;
+                final Object item;
+                if ((item = p.item) != null) {
+                    if (p.isData) {
+                        if (o.equals(item) && p.tryMatch(item, null)) {
+                            skipDeadNodes(pred, p, p, q);
+                            return true;
+                        }
+                        pred = p; p = q; continue;
+                    }
+                }
+                else if (!p.isData)
+                    break;
+                for (Node c = p;; q = p.next) {
+                    if (q == null || !q.isMatched()) {
+                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                    }
+                    if (p == (p = q)) continue restartFromHead;
+                }
+            }
+            return false;
+        }
     }
 
     /**
@@ -1499,18 +1535,29 @@
      * @return {@code true} if this queue contains the specified element
      */
     public boolean contains(Object o) {
-        if (o != null) {
-            for (Node p = head; p != null; p = succ(p)) {
-                Object item = p.item;
-                if (p.isData) {
-                    if (item != null && item != p && o.equals(item))
-                        return true;
+        if (o == null) return false;
+        restartFromHead: for (;;) {
+            for (Node p = head, pred = null; p != null; ) {
+                Node q = p.next;
+                final Object item;
+                if ((item = p.item) != null) {
+                    if (p.isData) {
+                        if (o.equals(item))
+                            return true;
+                        pred = p; p = q; continue;
+                    }
                 }
-                else if (item == null)
+                else if (!p.isData)
                     break;
+                for (Node c = p;; q = p.next) {
+                    if (q == null || !q.isMatched()) {
+                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                    }
+                    if (p == (p = q)) continue restartFromHead;
+                }
             }
+            return false;
         }
-        return false;
     }
 
     /**
@@ -1518,8 +1565,7 @@
      * {@code LinkedTransferQueue} is not capacity constrained.
      *
      * @return {@code Integer.MAX_VALUE} (as specified by
-     *         {@link java.util.concurrent.BlockingQueue#remainingCapacity()
-     *         BlockingQueue.remainingCapacity})
+     *         {@link BlockingQueue#remainingCapacity()})
      */
     public int remainingCapacity() {
         return Integer.MAX_VALUE;
@@ -1551,33 +1597,149 @@
      */
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
-        s.defaultReadObject();
-        for (;;) {
-            @SuppressWarnings("unchecked")
-            E item = (E) s.readObject();
-            if (item == null)
-                break;
+
+        // Read in elements until trailing null sentinel found
+        Node h = null, t = null;
+        for (Object item; (item = s.readObject()) != null; ) {
+            Node newNode = new Node(item);
+            if (h == null)
+                h = t = newNode;
             else
-                offer(item);
+                t.appendRelaxed(t = newNode);
+        }
+        if (h == null)
+            h = t = new Node();
+        head = h;
+        tail = t;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    public void clear() {
+        bulkRemove(e -> true);
+    }
+
+    /**
+     * Tolerate this many consecutive dead nodes before CAS-collapsing.
+     * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element.
+     */
+    private static final int MAX_HOPS = 8;
+
+    /** Implementation of bulk remove methods. */
+    @SuppressWarnings("unchecked")
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        restartFromHead: for (;;) {
+            int hops = MAX_HOPS;
+            // c will be CASed to collapse intervening dead nodes between
+            // pred (or head if null) and p.
+            for (Node p = head, c = p, pred = null, q; p != null; p = q) {
+                q = p.next;
+                final Object item; boolean pAlive;
+                if (pAlive = ((item = p.item) != null && p.isData)) {
+                    if (filter.test((E) item)) {
+                        if (p.tryMatch(item, null))
+                            removed = true;
+                        pAlive = false;
+                    }
+                }
+                else if (!p.isData && item == null)
+                    break;
+                if (pAlive || q == null || --hops == 0) {
+                    // p might already be self-linked here, but if so:
+                    // - CASing head will surely fail
+                    // - CASing pred's next will be useless but harmless.
+                    if ((c != p && !tryCasSuccessor(pred, c, c = p))
+                        || pAlive) {
+                        // if CAS failed or alive, abandon old pred
+                        hops = MAX_HOPS;
+                        pred = p;
+                        c = q;
+                    }
+                } else if (p == q)
+                    continue restartFromHead;
+            }
+            return removed;
         }
     }
 
-    // Unsafe mechanics
+    /**
+     * Runs action on each element found during a traversal starting at p.
+     * If p is null, the action is not run.
+     */
+    @SuppressWarnings("unchecked")
+    void forEachFrom(Consumer<? super E> action, Node p) {
+        for (Node pred = null; p != null; ) {
+            Node q = p.next;
+            final Object item;
+            if ((item = p.item) != null) {
+                if (p.isData) {
+                    action.accept((E) item);
+                    pred = p; p = q; continue;
+                }
+            }
+            else if (!p.isData)
+                break;
+            for (Node c = p;; q = p.next) {
+                if (q == null || !q.isMatched()) {
+                    pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                }
+                if (p == (p = q)) { pred = null; p = head; break; }
+            }
+        }
+    }
 
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long HEAD;
-    private static final long TAIL;
-    private static final long SWEEPVOTES;
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        forEachFrom(action, head);
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    private static final VarHandle SWEEPVOTES;
+    static final VarHandle ITEM;
+    static final VarHandle NEXT;
+    static final VarHandle WAITER;
     static {
         try {
-            HEAD = U.objectFieldOffset
-                (LinkedTransferQueue.class.getDeclaredField("head"));
-            TAIL = U.objectFieldOffset
-                (LinkedTransferQueue.class.getDeclaredField("tail"));
-            SWEEPVOTES = U.objectFieldOffset
-                (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(LinkedTransferQueue.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(LinkedTransferQueue.class, "tail",
+                                   Node.class);
+            SWEEPVOTES = l.findVarHandle(LinkedTransferQueue.class, "sweepVotes",
+                                         int.class);
+            ITEM = l.findVarHandle(Node.class, "item", Object.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/Phaser.java b/ojluni/src/main/java/java/util/concurrent/Phaser.java
index 9ef9936..76cd707 100644
--- a/ojluni/src/main/java/java/util/concurrent/Phaser.java
+++ b/ojluni/src/main/java/java/util/concurrent/Phaser.java
@@ -35,14 +35,15 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.LockSupport;
 
 /**
  * A reusable synchronization barrier, similar in functionality to
- * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and
- * {@link java.util.concurrent.CountDownLatch CountDownLatch}
- * but supporting more flexible usage.
+ * {@link CyclicBarrier} and {@link CountDownLatch} but supporting
+ * more flexible usage.
  *
  * <p><b>Registration.</b> Unlike the case for other barriers, the
  * number of parties <em>registered</em> to synchronize on a phaser
@@ -152,49 +153,46 @@
  * <p>A {@code Phaser} may be used instead of a {@code CountDownLatch}
  * to control a one-shot action serving a variable number of parties.
  * The typical idiom is for the method setting this up to first
- * register, then start the actions, then deregister, as in:
+ * register, then start all the actions, then deregister, as in:
  *
  * <pre> {@code
  * void runTasks(List<Runnable> tasks) {
- *   final Phaser phaser = new Phaser(1); // "1" to register self
+ *   Phaser startingGate = new Phaser(1); // "1" to register self
  *   // create and start threads
- *   for (final Runnable task : tasks) {
- *     phaser.register();
- *     new Thread() {
- *       public void run() {
- *         phaser.arriveAndAwaitAdvance(); // await all creation
- *         task.run();
- *       }
- *     }.start();
+ *   for (Runnable task : tasks) {
+ *     startingGate.register();
+ *     new Thread(() -> {
+ *       startingGate.arriveAndAwaitAdvance();
+ *       task.run();
+ *     }).start();
  *   }
  *
- *   // allow threads to start and deregister self
- *   phaser.arriveAndDeregister();
+ *   // deregister self to allow threads to proceed
+ *   startingGate.arriveAndDeregister();
  * }}</pre>
  *
  * <p>One way to cause a set of threads to repeatedly perform actions
  * for a given number of iterations is to override {@code onAdvance}:
  *
  * <pre> {@code
- * void startTasks(List<Runnable> tasks, final int iterations) {
- *   final Phaser phaser = new Phaser() {
+ * void startTasks(List<Runnable> tasks, int iterations) {
+ *   Phaser phaser = new Phaser() {
  *     protected boolean onAdvance(int phase, int registeredParties) {
- *       return phase >= iterations || registeredParties == 0;
+ *       return phase >= iterations - 1 || registeredParties == 0;
  *     }
  *   };
  *   phaser.register();
- *   for (final Runnable task : tasks) {
+ *   for (Runnable task : tasks) {
  *     phaser.register();
- *     new Thread() {
- *       public void run() {
- *         do {
- *           task.run();
- *           phaser.arriveAndAwaitAdvance();
- *         } while (!phaser.isTerminated());
- *       }
- *     }.start();
+ *     new Thread(() -> {
+ *       do {
+ *         task.run();
+ *         phaser.arriveAndAwaitAdvance();
+ *       } while (!phaser.isTerminated());
+ *     }).start();
  *   }
- *   phaser.arriveAndDeregister(); // deregister self, don't wait
+ *   // allow threads to proceed; don't wait for them
+ *   phaser.arriveAndDeregister();
  * }}</pre>
  *
  * If the main task must later await termination, it
@@ -221,7 +219,6 @@
  *   phaser.arriveAndDeregister();
  * }}</pre>
  *
- *
  * <p>To create a set of {@code n} tasks using a tree of phasers, you
  * could use code of the following form, assuming a Task class with a
  * constructor accepting a {@code Phaser} that it registers with upon
@@ -348,10 +345,6 @@
     private final AtomicReference<QNode> evenQ;
     private final AtomicReference<QNode> oddQ;
 
-    private AtomicReference<QNode> queueFor(int phase) {
-        return ((phase & 1) == 0) ? evenQ : oddQ;
-    }
-
     /**
      * Returns message string for bounds exceptions on arrival.
      */
@@ -388,7 +381,7 @@
             int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
             if (unarrived <= 0)
                 throw new IllegalStateException(badArrive(s));
-            if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
+            if (STATE.compareAndSet(this, s, s-=adjust)) {
                 if (unarrived == 1) {
                     long n = s & PARTIES_MASK;  // base of next state
                     int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@@ -401,12 +394,12 @@
                             n |= nextUnarrived;
                         int nextPhase = (phase + 1) & MAX_PHASE;
                         n |= (long)nextPhase << PHASE_SHIFT;
-                        U.compareAndSwapLong(this, STATE, s, n);
+                        STATE.compareAndSet(this, s, n);
                         releaseWaiters(phase);
                     }
                     else if (nextUnarrived == 0) { // propagate deregistration
                         phase = parent.doArrive(ONE_DEREGISTER);
-                        U.compareAndSwapLong(this, STATE, s, s | EMPTY);
+                        STATE.compareAndSet(this, s, s | EMPTY);
                     }
                     else
                         phase = parent.doArrive(ONE_ARRIVAL);
@@ -441,13 +434,13 @@
                 if (parent == null || reconcileState() == s) {
                     if (unarrived == 0)             // wait out advance
                         root.internalAwaitAdvance(phase, null);
-                    else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
+                    else if (STATE.compareAndSet(this, s, s + adjust))
                         break;
                 }
             }
             else if (parent == null) {              // 1st root registration
                 long next = ((long)phase << PHASE_SHIFT) | adjust;
-                if (U.compareAndSwapLong(this, STATE, s, next))
+                if (STATE.compareAndSet(this, s, next))
                     break;
             }
             else {
@@ -459,8 +452,8 @@
                         // finish registration whenever parent registration
                         // succeeded, even when racing with termination,
                         // since these are part of the same "transaction".
-                        while (!U.compareAndSwapLong
-                               (this, STATE, s,
+                        while (!STATE.weakCompareAndSet
+                               (this, s,
                                 ((long)phase << PHASE_SHIFT) | adjust)) {
                             s = state;
                             phase = (int)(root.state >>> PHASE_SHIFT);
@@ -491,8 +484,8 @@
             // CAS to root phase with current parties, tripping unarrived
             while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
                    (int)(s >>> PHASE_SHIFT) &&
-                   !U.compareAndSwapLong
-                   (this, STATE, s,
+                   !STATE.weakCompareAndSet
+                   (this, s,
                     s = (((long)phase << PHASE_SHIFT) |
                          ((phase < 0) ? (s & COUNTS_MASK) :
                           (((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@@ -681,7 +674,7 @@
             int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
             if (unarrived <= 0)
                 throw new IllegalStateException(badArrive(s));
-            if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
+            if (STATE.compareAndSet(this, s, s -= ONE_ARRIVAL)) {
                 if (unarrived > 1)
                     return root.internalAwaitAdvance(phase, null);
                 if (root != this)
@@ -696,7 +689,7 @@
                     n |= nextUnarrived;
                 int nextPhase = (phase + 1) & MAX_PHASE;
                 n |= (long)nextPhase << PHASE_SHIFT;
-                if (!U.compareAndSwapLong(this, STATE, s, n))
+                if (!STATE.compareAndSet(this, s, n))
                     return (int)(state >>> PHASE_SHIFT); // terminated
                 releaseWaiters(phase);
                 return nextPhase;
@@ -812,7 +805,7 @@
         final Phaser root = this.root;
         long s;
         while ((s = root.state) >= 0) {
-            if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
+            if (STATE.compareAndSet(root, s, s | TERMINATION_BIT)) {
                 // signal all threads
                 releaseWaiters(0); // Waiters on evenQ
                 releaseWaiters(1); // Waiters on oddQ
@@ -1047,6 +1040,9 @@
                     node = new QNode(this, phase, false, false, 0L);
                     node.wasInterrupted = interrupted;
                 }
+                // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+                // else
+                //     Thread.onSpinWait();
             }
             else if (node.isReleasable()) // done or aborted
                 break;
@@ -1135,16 +1131,14 @@
         }
     }
 
-    // Unsafe mechanics
-
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long STATE;
+    // VarHandle mechanics
+    private static final VarHandle STATE;
     static {
         try {
-            STATE = U.objectFieldOffset
-                (Phaser.class.getDeclaredField("state"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(Phaser.class, "state", long.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
index 644de86..03a17e5 100644
--- a/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
@@ -35,12 +35,15 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.PriorityQueue;
 import java.util.Queue;
 import java.util.SortedSet;
@@ -48,10 +51,8 @@
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
+import jdk.internal.misc.SharedSecrets;
 
 /**
  * An unbounded {@linkplain BlockingQueue blocking queue} that uses
@@ -64,15 +65,15 @@
  * non-comparable objects (doing so results in
  * {@code ClassCastException}).
  *
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.  The Iterator provided in method {@link
- * #iterator()} is <em>not</em> guaranteed to traverse the elements of
- * the PriorityBlockingQueue in any particular order. If you need
- * ordered traversal, consider using
- * {@code Arrays.sort(pq.toArray())}.  Also, method {@code drainTo}
- * can be used to <em>remove</em> some or all elements in priority
- * order and place them in another collection.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ * The Iterator provided in method {@link #iterator()} and the
+ * Spliterator provided in method {@link #spliterator()} are <em>not</em>
+ * guaranteed to traverse the elements of the PriorityBlockingQueue in
+ * any particular order. If you need ordered traversal, consider using
+ * {@code Arrays.sort(pq.toArray())}.  Also, method {@code drainTo} can
+ * be used to <em>remove</em> some or all elements in priority order and
+ * place them in another collection.
  *
  * <p>Operations on this class make no guarantees about the ordering
  * of elements with equal priority. If you need to enforce an
@@ -101,6 +102,10 @@
  *   }
  * }}</pre>
  *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
@@ -163,12 +168,12 @@
     /**
      * Lock used for all public operations.
      */
-    private final ReentrantLock lock;
+    private final ReentrantLock lock = new ReentrantLock();
 
     /**
      * Condition for blocking when empty.
      */
-    private final Condition notEmpty;
+    private final Condition notEmpty = lock.newCondition();
 
     /**
      * Spinlock for allocation, acquired via CAS.
@@ -220,10 +225,8 @@
                                  Comparator<? super E> comparator) {
         if (initialCapacity < 1)
             throw new IllegalArgumentException();
-        this.lock = new ReentrantLock();
-        this.notEmpty = lock.newCondition();
         this.comparator = comparator;
-        this.queue = new Object[initialCapacity];
+        this.queue = new Object[Math.max(1, initialCapacity)];
     }
 
     /**
@@ -243,8 +246,6 @@
      *         of its elements are null
      */
     public PriorityBlockingQueue(Collection<? extends E> c) {
-        this.lock = new ReentrantLock();
-        this.notEmpty = lock.newCondition();
         boolean heapify = true; // true if not known to be in heap order
         boolean screen = true;  // true if must screen for nulls
         if (c instanceof SortedSet<?>) {
@@ -260,22 +261,27 @@
             if (pq.getClass() == PriorityBlockingQueue.class) // exact match
                 heapify = false;
         }
-        Object[] a = c.toArray();
-        int n = a.length;
+        Object[] es = c.toArray();
+        int n = es.length;
         // If c.toArray incorrectly doesn't return Object[], copy it.
-        if (a.getClass() != Object[].class)
-            a = Arrays.copyOf(a, n, Object[].class);
+        if (es.getClass() != Object[].class)
+            es = Arrays.copyOf(es, n, Object[].class);
         if (screen && (n == 1 || this.comparator != null)) {
-            for (int i = 0; i < n; ++i)
-                if (a[i] == null)
+            for (Object e : es)
+                if (e == null)
                     throw new NullPointerException();
         }
-        this.queue = a;
+        this.queue = ensureNonEmpty(es);
         this.size = n;
         if (heapify)
             heapify();
     }
 
+    /** Ensures that queue[0] exists, helping peek() and poll(). */
+    private static Object[] ensureNonEmpty(Object[] es) {
+        return (es.length > 0) ? es : new Object[1];
+    }
+
     /**
      * Tries to grow array to accommodate at least one more element
      * (but normally expand by about 50%), giving up (allowing retry)
@@ -289,7 +295,7 @@
         lock.unlock(); // must release and then re-acquire main lock
         Object[] newArray = null;
         if (allocationSpinLock == 0 &&
-            U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
+            ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
             try {
                 int newCap = oldCap + ((oldCap < 64) ?
                                        (oldCap + 2) : // grow faster if small
@@ -319,22 +325,23 @@
      * Mechanics for poll().  Call only while holding lock.
      */
     private E dequeue() {
-        int n = size - 1;
-        if (n < 0)
-            return null;
-        else {
-            Object[] array = queue;
-            E result = (E) array[0];
-            E x = (E) array[n];
-            array[n] = null;
-            Comparator<? super E> cmp = comparator;
-            if (cmp == null)
-                siftDownComparable(0, x, array, n);
-            else
-                siftDownUsingComparator(0, x, array, n, cmp);
-            size = n;
-            return result;
+        // assert lock.isHeldByCurrentThread();
+        final Object[] es;
+        final E result;
+
+        if ((result = (E) ((es = queue)[0])) != null) {
+            final int n;
+            final E x = (E) es[(n = --size)];
+            es[n] = null;
+            if (n > 0) {
+                final Comparator<? super E> cmp;
+                if ((cmp = comparator) == null)
+                    siftDownComparable(0, x, es, n);
+                else
+                    siftDownUsingComparator(0, x, es, n, cmp);
+            }
         }
+        return result;
     }
 
     /**
@@ -342,40 +349,38 @@
      * promoting x up the tree until it is greater than or equal to
      * its parent, or is the root.
      *
-     * To simplify and speed up coercions and comparisons. the
+     * To simplify and speed up coercions and comparisons, the
      * Comparable and Comparator versions are separated into different
      * methods that are otherwise identical. (Similarly for siftDown.)
-     * These methods are static, with heap state as arguments, to
-     * simplify use in light of possible comparator exceptions.
      *
      * @param k the position to fill
      * @param x the item to insert
-     * @param array the heap array
+     * @param es the heap array
      */
-    private static <T> void siftUpComparable(int k, T x, Object[] array) {
+    private static <T> void siftUpComparable(int k, T x, Object[] es) {
         Comparable<? super T> key = (Comparable<? super T>) x;
         while (k > 0) {
             int parent = (k - 1) >>> 1;
-            Object e = array[parent];
+            Object e = es[parent];
             if (key.compareTo((T) e) >= 0)
                 break;
-            array[k] = e;
+            es[k] = e;
             k = parent;
         }
-        array[k] = key;
+        es[k] = key;
     }
 
-    private static <T> void siftUpUsingComparator(int k, T x, Object[] array,
-                                       Comparator<? super T> cmp) {
+    private static <T> void siftUpUsingComparator(
+        int k, T x, Object[] es, Comparator<? super T> cmp) {
         while (k > 0) {
             int parent = (k - 1) >>> 1;
-            Object e = array[parent];
+            Object e = es[parent];
             if (cmp.compare(x, (T) e) >= 0)
                 break;
-            array[k] = e;
+            es[k] = e;
             k = parent;
         }
-        array[k] = x;
+        es[k] = x;
     }
 
     /**
@@ -385,67 +390,61 @@
      *
      * @param k the position to fill
      * @param x the item to insert
-     * @param array the heap array
+     * @param es the heap array
      * @param n heap size
      */
-    private static <T> void siftDownComparable(int k, T x, Object[] array,
-                                               int n) {
-        if (n > 0) {
-            Comparable<? super T> key = (Comparable<? super T>)x;
-            int half = n >>> 1;           // loop while a non-leaf
-            while (k < half) {
-                int child = (k << 1) + 1; // assume left child is least
-                Object c = array[child];
-                int right = child + 1;
-                if (right < n &&
-                    ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
-                    c = array[child = right];
-                if (key.compareTo((T) c) <= 0)
-                    break;
-                array[k] = c;
-                k = child;
-            }
-            array[k] = key;
+    private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
+        // assert n > 0;
+        Comparable<? super T> key = (Comparable<? super T>)x;
+        int half = n >>> 1;           // loop while a non-leaf
+        while (k < half) {
+            int child = (k << 1) + 1; // assume left child is least
+            Object c = es[child];
+            int right = child + 1;
+            if (right < n &&
+                ((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
+                c = es[child = right];
+            if (key.compareTo((T) c) <= 0)
+                break;
+            es[k] = c;
+            k = child;
         }
+        es[k] = key;
     }
 
-    private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
-                                                    int n,
-                                                    Comparator<? super T> cmp) {
-        if (n > 0) {
-            int half = n >>> 1;
-            while (k < half) {
-                int child = (k << 1) + 1;
-                Object c = array[child];
-                int right = child + 1;
-                if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
-                    c = array[child = right];
-                if (cmp.compare(x, (T) c) <= 0)
-                    break;
-                array[k] = c;
-                k = child;
-            }
-            array[k] = x;
+    private static <T> void siftDownUsingComparator(
+        int k, T x, Object[] es, int n, Comparator<? super T> cmp) {
+        // assert n > 0;
+        int half = n >>> 1;
+        while (k < half) {
+            int child = (k << 1) + 1;
+            Object c = es[child];
+            int right = child + 1;
+            if (right < n && cmp.compare((T) c, (T) es[right]) > 0)
+                c = es[child = right];
+            if (cmp.compare(x, (T) c) <= 0)
+                break;
+            es[k] = c;
+            k = child;
         }
+        es[k] = x;
     }
 
     /**
      * Establishes the heap invariant (described above) in the entire tree,
      * assuming nothing about the order of the elements prior to the call.
+     * This classic algorithm due to Floyd (1964) is known to be O(size).
      */
     private void heapify() {
-        Object[] array = queue;
-        int n = size;
-        int half = (n >>> 1) - 1;
-        Comparator<? super E> cmp = comparator;
-        if (cmp == null) {
-            for (int i = half; i >= 0; i--)
-                siftDownComparable(i, (E) array[i], array, n);
-        }
-        else {
-            for (int i = half; i >= 0; i--)
-                siftDownUsingComparator(i, (E) array[i], array, n, cmp);
-        }
+        final Object[] es = queue;
+        int n = size, i = (n >>> 1) - 1;
+        final Comparator<? super E> cmp;
+        if ((cmp = comparator) == null)
+            for (; i >= 0; i--)
+                siftDownComparable(i, (E) es[i], es, n);
+        else
+            for (; i >= 0; i--)
+                siftDownUsingComparator(i, (E) es[i], es, n, cmp);
     }
 
     /**
@@ -479,15 +478,15 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         int n, cap;
-        Object[] array;
-        while ((n = size) >= (cap = (array = queue).length))
-            tryGrow(array, cap);
+        Object[] es;
+        while ((n = size) >= (cap = (es = queue).length))
+            tryGrow(es, cap);
         try {
-            Comparator<? super E> cmp = comparator;
-            if (cmp == null)
-                siftUpComparable(n, e, array);
+            final Comparator<? super E> cmp;
+            if ((cmp = comparator) == null)
+                siftUpComparable(n, e, es);
             else
-                siftUpUsingComparator(n, e, array, cmp);
+                siftUpUsingComparator(n, e, es, cmp);
             size = n + 1;
             notEmpty.signal();
         } finally {
@@ -570,7 +569,7 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            return (size == 0) ? null : (E) queue[0];
+            return (E) queue[0];
         } finally {
             lock.unlock();
         }
@@ -610,10 +609,9 @@
 
     private int indexOf(Object o) {
         if (o != null) {
-            Object[] array = queue;
-            int n = size;
-            for (int i = 0; i < n; i++)
-                if (o.equals(array[i]))
+            final Object[] es = queue;
+            for (int i = 0, n = size; i < n; i++)
+                if (o.equals(es[i]))
                     return i;
         }
         return -1;
@@ -623,23 +621,23 @@
      * Removes the ith element from queue.
      */
     private void removeAt(int i) {
-        Object[] array = queue;
-        int n = size - 1;
+        final Object[] es = queue;
+        final int n = size - 1;
         if (n == i) // removed last element
-            array[i] = null;
+            es[i] = null;
         else {
-            E moved = (E) array[n];
-            array[n] = null;
-            Comparator<? super E> cmp = comparator;
-            if (cmp == null)
-                siftDownComparable(i, moved, array, n);
+            E moved = (E) es[n];
+            es[n] = null;
+            final Comparator<? super E> cmp;
+            if ((cmp = comparator) == null)
+                siftDownComparable(i, moved, es, n);
             else
-                siftDownUsingComparator(i, moved, array, n, cmp);
-            if (array[i] == moved) {
+                siftDownUsingComparator(i, moved, es, n, cmp);
+            if (es[i] == moved) {
                 if (cmp == null)
-                    siftUpComparable(i, moved, array);
+                    siftUpComparable(i, moved, es);
                 else
-                    siftUpUsingComparator(i, moved, array, cmp);
+                    siftUpUsingComparator(i, moved, es, cmp);
             }
         }
         size = n;
@@ -672,14 +670,16 @@
 
     /**
      * Identity-based version for use in Itr.remove.
+     *
+     * @param o element to be removed from this queue, if present
      */
-    void removeEQ(Object o) {
+    void removeEq(Object o) {
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            Object[] array = queue;
+            final Object[] es = queue;
             for (int i = 0, n = size; i < n; i++) {
-                if (o == array[i]) {
+                if (o == es[i]) {
                     removeAt(i);
                     break;
                 }
@@ -728,8 +728,7 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        if (c == null)
-            throw new NullPointerException();
+        Objects.requireNonNull(c);
         if (c == this)
             throw new IllegalArgumentException();
         if (maxElements <= 0)
@@ -756,11 +755,10 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            Object[] array = queue;
-            int n = size;
+            final Object[] es = queue;
+            for (int i = 0, n = size; i < n; i++)
+                es[i] = null;
             size = 0;
-            for (int i = 0; i < n; i++)
-                array[i] = null;
         } finally {
             lock.unlock();
         }
@@ -861,10 +859,9 @@
     final class Itr implements Iterator<E> {
         final Object[] array; // Array of all elements
         int cursor;           // index of next element to return
-        int lastRet;          // index of last element, or -1 if no such
+        int lastRet = -1;     // index of last element, or -1 if no such
 
         Itr(Object[] array) {
-            lastRet = -1;
             this.array = array;
         }
 
@@ -875,16 +872,28 @@
         public E next() {
             if (cursor >= array.length)
                 throw new NoSuchElementException();
-            lastRet = cursor;
-            return (E)array[cursor++];
+            return (E)array[lastRet = cursor++];
         }
 
         public void remove() {
             if (lastRet < 0)
                 throw new IllegalStateException();
-            removeEQ(array[lastRet]);
+            removeEq(array[lastRet]);
             lastRet = -1;
         }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final Object[] es = array;
+            int i;
+            if ((i = cursor) < es.length) {
+                lastRet = -1;
+                cursor = es.length;
+                for (; i < es.length; i++)
+                    action.accept((E) es[i]);
+                lastRet = es.length - 1;
+            }
+        }
     }
 
     /**
@@ -922,7 +931,9 @@
         throws java.io.IOException, ClassNotFoundException {
         try {
             s.defaultReadObject();
-            this.queue = new Object[q.size()];
+            int sz = q.size();
+            SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, sz);
+            this.queue = new Object[Math.max(1, sz)];
             comparator = q.comparator();
             addAll(q);
         } finally {
@@ -930,68 +941,65 @@
         }
     }
 
-    // Similar to Collections.ArraySnapshotSpliterator but avoids
-    // commitment to toArray until needed
-    static final class PBQSpliterator<E> implements Spliterator<E> {
-        final PriorityBlockingQueue<E> queue;
-        Object[] array;
+    /**
+     * Immutable snapshot spliterator that binds to elements "late".
+     */
+    final class PBQSpliterator implements Spliterator<E> {
+        Object[] array;        // null until late-bound-initialized
         int index;
         int fence;
 
-        PBQSpliterator(PriorityBlockingQueue<E> queue, Object[] array,
-                       int index, int fence) {
-            this.queue = queue;
+        PBQSpliterator() {}
+
+        PBQSpliterator(Object[] array, int index, int fence) {
             this.array = array;
             this.index = index;
             this.fence = fence;
         }
 
-        final int getFence() {
-            int hi;
-            if ((hi = fence) < 0)
-                hi = fence = (array = queue.toArray()).length;
-            return hi;
+        private int getFence() {
+            if (array == null)
+                fence = (array = toArray()).length;
+            return fence;
         }
 
-        public PBQSpliterator<E> trySplit() {
+        public PBQSpliterator trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
             return (lo >= mid) ? null :
-                new PBQSpliterator<E>(queue, array, lo, index = mid);
+                new PBQSpliterator(array, lo, index = mid);
         }
 
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
-            Object[] a; int i, hi; // hoist accesses and checks from loop
-            if (action == null)
-                throw new NullPointerException();
-            if ((a = array) == null)
-                fence = (a = queue.toArray()).length;
-            if ((hi = fence) <= a.length &&
-                (i = index) >= 0 && i < (index = hi)) {
-                do { action.accept((E)a[i]); } while (++i < hi);
-            }
+            Objects.requireNonNull(action);
+            final int hi = getFence(), lo = index;
+            final Object[] es = array;
+            index = hi;                 // ensure exhaustion
+            for (int i = lo; i < hi; i++)
+                action.accept((E) es[i]);
         }
 
         public boolean tryAdvance(Consumer<? super E> action) {
-            if (action == null)
-                throw new NullPointerException();
+            Objects.requireNonNull(action);
             if (getFence() > index && index >= 0) {
-                @SuppressWarnings("unchecked") E e = (E) array[index++];
-                action.accept(e);
+                action.accept((E) array[index++]);
                 return true;
             }
             return false;
         }
 
-        public long estimateSize() { return (long)(getFence() - index); }
+        public long estimateSize() { return getFence() - index; }
 
         public int characteristics() {
-            return Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED;
+            return (Spliterator.NONNULL |
+                    Spliterator.SIZED |
+                    Spliterator.SUBSIZED);
         }
     }
 
     /**
      * Returns a {@link Spliterator} over the elements in this queue.
+     * The spliterator does not traverse elements in any particular order
+     * (the {@link Spliterator#ORDERED ORDERED} characteristic is not reported).
      *
      * <p>The returned spliterator is
      * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
@@ -1006,18 +1014,106 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new PBQSpliterator<E>(this, null, 0, -1);
+        return new PBQSpliterator();
     }
 
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long ALLOCATIONSPINLOCK;
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] es = queue;
+            final int end = size;
+            int i;
+            // Optimize for initial run of survivors
+            for (i = 0; i < end && !filter.test((E) es[i]); i++)
+                ;
+            if (i >= end)
+                return false;
+            // Tolerate predicates that reentrantly access the
+            // collection for read, so traverse once to find elements
+            // to delete, a second pass to physically expunge.
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test((E) es[i]))
+                    setBit(deathRow, i - beg);
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    es[w++] = es[i];
+            for (i = size = w; i < end; i++)
+                es[i] = null;
+            heapify();
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] es = queue;
+            for (int i = 0, n = size; i < n; i++)
+                action.accept((E) es[i]);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle ALLOCATIONSPINLOCK;
     static {
         try {
-            ALLOCATIONSPINLOCK = U.objectFieldOffset
-                (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            ALLOCATIONSPINLOCK = l.findVarHandle(PriorityBlockingQueue.class,
+                                                 "allocationSpinLock",
+                                                 int.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java b/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
index 6b9fcc3..be75ff4 100644
--- a/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
+++ b/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
@@ -77,14 +77,11 @@
  *     Executors.newScheduledThreadPool(1);
  *
  *   public void beepForAnHour() {
- *     final Runnable beeper = new Runnable() {
- *       public void run() { System.out.println("beep"); }
- *     };
- *     final ScheduledFuture&lt;?&lt; beeperHandle =
+ *     Runnable beeper = () -> System.out.println("beep");
+ *     ScheduledFuture<?> beeperHandle =
  *       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
- *     scheduler.schedule(new Runnable() {
- *       public void run() { beeperHandle.cancel(true); }
- *     }, 60 * 60, SECONDS);
+ *     Runnable canceller = () -> beeperHandle.cancel(false);
+ *     scheduler.schedule(canceller, 1, HOURS);
  *   }
  * }}</pre>
  *
@@ -94,8 +91,7 @@
 public interface ScheduledExecutorService extends ExecutorService {
 
     /**
-     * Creates and executes a one-shot action that becomes enabled
-     * after the given delay.
+     * Submits a one-shot task that becomes enabled after the given delay.
      *
      * @param command the task to execute
      * @param delay the time from now to delay execution
@@ -105,14 +101,14 @@
      *         {@code null} upon completion
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
-     * @throws NullPointerException if command is null
+     * @throws NullPointerException if command or unit is null
      */
     public ScheduledFuture<?> schedule(Runnable command,
                                        long delay, TimeUnit unit);
 
     /**
-     * Creates and executes a ScheduledFuture that becomes enabled after the
-     * given delay.
+     * Submits a value-returning one-shot task that becomes enabled
+     * after the given delay.
      *
      * @param callable the function to execute
      * @param delay the time from now to delay execution
@@ -121,15 +117,15 @@
      * @return a ScheduledFuture that can be used to extract result or cancel
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
-     * @throws NullPointerException if callable is null
+     * @throws NullPointerException if callable or unit is null
      */
     public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                            long delay, TimeUnit unit);
 
     /**
-     * Creates and executes a periodic action that becomes enabled first
-     * after the given initial delay, and subsequently with the given
-     * period; that is, executions will commence after
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given period;
+     * that is, executions will commence after
      * {@code initialDelay}, then {@code initialDelay + period}, then
      * {@code initialDelay + 2 * period}, and so on.
      *
@@ -140,8 +136,8 @@
      * via the returned future.
      * <li>The executor terminates, also resulting in task cancellation.
      * <li>An execution of the task throws an exception.  In this case
-     * calling {@link Future#get() get} on the returned future will
-     * throw {@link ExecutionException}.
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
      * </ul>
      * Subsequent executions are suppressed.  Subsequent calls to
      * {@link Future#isDone isDone()} on the returned future will
@@ -162,7 +158,7 @@
      *         abnormal termination of a task execution.
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
-     * @throws NullPointerException if command is null
+     * @throws NullPointerException if command or unit is null
      * @throws IllegalArgumentException if period less than or equal to zero
      */
     public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
@@ -171,10 +167,10 @@
                                                   TimeUnit unit);
 
     /**
-     * Creates and executes a periodic action that becomes enabled first
-     * after the given initial delay, and subsequently with the
-     * given delay between the termination of one execution and the
-     * commencement of the next.
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given delay
+     * between the termination of one execution and the commencement of
+     * the next.
      *
      * <p>The sequence of task executions continues indefinitely until
      * one of the following exceptional completions occur:
@@ -183,8 +179,8 @@
      * via the returned future.
      * <li>The executor terminates, also resulting in task cancellation.
      * <li>An execution of the task throws an exception.  In this case
-     * calling {@link Future#get() get} on the returned future will
-     * throw {@link ExecutionException}.
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
      * </ul>
      * Subsequent executions are suppressed.  Subsequent calls to
      * {@link Future#isDone isDone()} on the returned future will
@@ -202,7 +198,7 @@
      *         abnormal termination of a task execution.
      * @throws RejectedExecutionException if the task cannot be
      *         scheduled for execution
-     * @throws NullPointerException if command is null
+     * @throws NullPointerException if command or unit is null
      * @throws IllegalArgumentException if delay less than or equal to zero
      */
     public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
diff --git a/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index 4249872..192df25 100644
--- a/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -44,6 +44,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
@@ -89,6 +90,11 @@
  * use {@code allowCoreThreadTimeOut} because this may leave the pool
  * without threads to handle tasks once they become eligible to run.
  *
+ * <p>As with {@code ThreadPoolExecutor}, if not otherwise specified,
+ * this class uses {@link Executors#defaultThreadFactory} as the
+ * default thread factory, and {@link ThreadPoolExecutor.AbortPolicy}
+ * as the default rejected execution handler.
+ *
  * <p><b>Extension notes:</b> This class overrides the
  * {@link ThreadPoolExecutor#execute(Runnable) execute} and
  * {@link AbstractExecutorService#submit(Runnable) submit}
@@ -162,6 +168,7 @@
      */
     private volatile boolean continueExistingPeriodicTasksAfterShutdown;
 
+    // Android-changed: Preserving behaviour on expired tasks (b/202927404)
     /**
      * False if should cancel non-periodic tasks on shutdown.
      */
@@ -294,10 +301,9 @@
          * Overrides FutureTask version so as to reset/requeue if periodic.
          */
         public void run() {
-            boolean periodic = isPeriodic();
-            if (!canRunInCurrentRunState(periodic))
+            if (!canRunInCurrentRunState(this))
                 cancel(false);
-            else if (!periodic)
+            else if (!isPeriodic())
                 super.run();
             else if (super.runAndReset()) {
                 setNextRunTime();
@@ -307,15 +313,20 @@
     }
 
     /**
-     * Returns true if can run a task given current run state
-     * and run-after-shutdown parameters.
-     *
-     * @param periodic true if this task periodic, false if delayed
+     * Returns true if can run a task given current run state and
+     * run-after-shutdown parameters.
      */
-    boolean canRunInCurrentRunState(boolean periodic) {
-        return isRunningOrShutdown(periodic ?
-                                   continueExistingPeriodicTasksAfterShutdown :
-                                   executeExistingDelayedTasksAfterShutdown);
+    boolean canRunInCurrentRunState(RunnableScheduledFuture<?> task) {
+        if (!isShutdown())
+            return true;
+        if (isStopped())
+            return false;
+        return task.isPeriodic()
+            ? continueExistingPeriodicTasksAfterShutdown
+            : (executeExistingDelayedTasksAfterShutdown
+            // Android-changed: Preserving behaviour on expired tasks (b/202927404)
+            //   || task.getDelay(NANOSECONDS) <= 0);
+              );
     }
 
     /**
@@ -334,9 +345,7 @@
             reject(task);
         else {
             super.getQueue().add(task);
-            if (isShutdown() &&
-                !canRunInCurrentRunState(task.isPeriodic()) &&
-                remove(task))
+            if (!canRunInCurrentRunState(task) && remove(task))
                 task.cancel(false);
             else
                 ensurePrestart();
@@ -350,13 +359,14 @@
      * @param task the task
      */
     void reExecutePeriodic(RunnableScheduledFuture<?> task) {
-        if (canRunInCurrentRunState(true)) {
+        if (canRunInCurrentRunState(task)) {
             super.getQueue().add(task);
-            if (!canRunInCurrentRunState(true) && remove(task))
-                task.cancel(false);
-            else
+            if (canRunInCurrentRunState(task) || !remove(task)) {
                 ensurePrestart();
+                return;
+            }
         }
+        task.cancel(false);
     }
 
     /**
@@ -369,23 +379,20 @@
             getExecuteExistingDelayedTasksAfterShutdownPolicy();
         boolean keepPeriodic =
             getContinueExistingPeriodicTasksAfterShutdownPolicy();
-        if (!keepDelayed && !keepPeriodic) {
-            for (Object e : q.toArray())
-                if (e instanceof RunnableScheduledFuture<?>)
-                    ((RunnableScheduledFuture<?>) e).cancel(false);
-            q.clear();
-        }
-        else {
-            // Traverse snapshot to avoid iterator exceptions
-            for (Object e : q.toArray()) {
-                if (e instanceof RunnableScheduledFuture) {
-                    RunnableScheduledFuture<?> t =
-                        (RunnableScheduledFuture<?>)e;
-                    if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||
-                        t.isCancelled()) { // also remove if already cancelled
-                        if (q.remove(t))
-                            t.cancel(false);
-                    }
+        // Traverse snapshot to avoid iterator exceptions
+        // TODO: implement and use efficient removeIf
+        // super.getQueue().removeIf(...);
+        for (Object e : q.toArray()) {
+            if (e instanceof RunnableScheduledFuture) {
+                RunnableScheduledFuture<?> t = (RunnableScheduledFuture<?>)e;
+                if ((t.isPeriodic()
+                     ? !keepPeriodic
+                     // Android-changed: Preserving behaviour on expired tasks (b/202927404)
+                     // : (!keepDelayed && t.getDelay(NANOSECONDS) > 0))
+                     : !keepDelayed)
+                    || t.isCancelled()) { // also remove if already cancelled
+                    if (q.remove(t))
+                        t.cancel(false);
                 }
             }
         }
@@ -581,6 +588,34 @@
     }
 
     /**
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given period;
+     * that is, executions will commence after
+     * {@code initialDelay}, then {@code initialDelay + period}, then
+     * {@code initialDelay + 2 * period}, and so on.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>Method {@link #shutdown} is called and the {@linkplain
+     * #getContinueExistingPeriodicTasksAfterShutdownPolicy policy on
+     * whether to continue after shutdown} is not set true, or method
+     * {@link #shutdownNow} is called; also resulting in task
+     * cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * <p>If any execution of this task takes longer than its period, then
+     * subsequent executions may start late, but will not concurrently
+     * execute.
+     *
      * @throws RejectedExecutionException {@inheritDoc}
      * @throws NullPointerException       {@inheritDoc}
      * @throws IllegalArgumentException   {@inheritDoc}
@@ -606,6 +641,29 @@
     }
 
     /**
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given delay
+     * between the termination of one execution and the commencement of
+     * the next.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>Method {@link #shutdown} is called and the {@linkplain
+     * #getContinueExistingPeriodicTasksAfterShutdownPolicy policy on
+     * whether to continue after shutdown} is not set true, or method
+     * {@link #shutdownNow} is called; also resulting in task
+     * cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
      * @throws RejectedExecutionException {@inheritDoc}
      * @throws NullPointerException       {@inheritDoc}
      * @throws IllegalArgumentException   {@inheritDoc}
@@ -683,9 +741,8 @@
     /**
      * Sets the policy on whether to continue executing existing
      * periodic tasks even when this executor has been {@code shutdown}.
-     * In this case, these tasks will only terminate upon
-     * {@code shutdownNow} or after setting the policy to
-     * {@code false} when already shutdown.
+     * In this case, executions will continue until {@code shutdownNow}
+     * or the policy is set to {@code false} when already shutdown.
      * This value is by default {@code false}.
      *
      * @param value if {@code true}, continue after shutdown, else don't
@@ -700,9 +757,8 @@
     /**
      * Gets the policy on whether to continue executing existing
      * periodic tasks even when this executor has been {@code shutdown}.
-     * In this case, these tasks will only terminate upon
-     * {@code shutdownNow} or after setting the policy to
-     * {@code false} when already shutdown.
+     * In this case, executions will continue until {@code shutdownNow}
+     * or the policy is set to {@code false} when already shutdown.
      * This value is by default {@code false}.
      *
      * @return {@code true} if will continue after shutdown
@@ -905,7 +961,7 @@
         /**
          * Sets f's heapIndex if it is a ScheduledFutureTask.
          */
-        private void setIndex(RunnableScheduledFuture<?> f, int idx) {
+        private static void setIndex(RunnableScheduledFuture<?> f, int idx) {
             if (f instanceof ScheduledFutureTask)
                 ((ScheduledFutureTask)f).heapIndex = idx;
         }
@@ -1203,41 +1259,12 @@
             }
         }
 
-        /**
-         * Returns first element only if it is expired.
-         * Used only by drainTo.  Call only when holding lock.
-         */
-        private RunnableScheduledFuture<?> peekExpired() {
-            // assert lock.isHeldByCurrentThread();
-            RunnableScheduledFuture<?> first = queue[0];
-            return (first == null || first.getDelay(NANOSECONDS) > 0) ?
-                null : first;
-        }
-
         public int drainTo(Collection<? super Runnable> c) {
-            if (c == null)
-                throw new NullPointerException();
-            if (c == this)
-                throw new IllegalArgumentException();
-            final ReentrantLock lock = this.lock;
-            lock.lock();
-            try {
-                RunnableScheduledFuture<?> first;
-                int n = 0;
-                while ((first = peekExpired()) != null) {
-                    c.add(first);   // In this order, in case add() throws.
-                    finishPoll(first);
-                    ++n;
-                }
-                return n;
-            } finally {
-                lock.unlock();
-            }
+            return drainTo(c, Integer.MAX_VALUE);
         }
 
         public int drainTo(Collection<? super Runnable> c, int maxElements) {
-            if (c == null)
-                throw new NullPointerException();
+            Objects.requireNonNull(c);
             if (c == this)
                 throw new IllegalArgumentException();
             if (maxElements <= 0)
@@ -1245,9 +1272,11 @@
             final ReentrantLock lock = this.lock;
             lock.lock();
             try {
-                RunnableScheduledFuture<?> first;
                 int n = 0;
-                while (n < maxElements && (first = peekExpired()) != null) {
+                for (RunnableScheduledFuture<?> first;
+                     n < maxElements
+                         && (first = queue[0]) != null
+                         && first.getDelay(NANOSECONDS) <= 0;) {
                     c.add(first);   // In this order, in case add() throws.
                     finishPoll(first);
                     ++n;
@@ -1285,7 +1314,13 @@
         }
 
         public Iterator<Runnable> iterator() {
-            return new Itr(Arrays.copyOf(queue, size));
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return new Itr(Arrays.copyOf(queue, size));
+            } finally {
+                lock.unlock();
+            }
         }
 
         /**
@@ -1307,8 +1342,7 @@
             public Runnable next() {
                 if (cursor >= array.length)
                     throw new NoSuchElementException();
-                lastRet = cursor;
-                return array[cursor++];
+                return array[lastRet = cursor++];
             }
 
             public void remove() {
diff --git a/ojluni/src/main/java/java/util/concurrent/Semaphore.java b/ojluni/src/main/java/java/util/concurrent/Semaphore.java
index 1298a6e..86ee638 100644
--- a/ojluni/src/main/java/java/util/concurrent/Semaphore.java
+++ b/ojluni/src/main/java/java/util/concurrent/Semaphore.java
@@ -72,8 +72,8 @@
  *   protected synchronized Object getNextAvailableItem() {
  *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
  *       if (!used[i]) {
- *          used[i] = true;
- *          return items[i];
+ *         used[i] = true;
+ *         return items[i];
  *       }
  *     }
  *     return null; // not reached
@@ -82,11 +82,11 @@
  *   protected synchronized boolean markAsUnused(Object item) {
  *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
  *       if (item == items[i]) {
- *          if (used[i]) {
- *            used[i] = false;
- *            return true;
- *          } else
- *            return false;
+ *         if (used[i]) {
+ *           used[i] = false;
+ *           return true;
+ *         } else
+ *           return false;
  *       }
  *     }
  *     return false;
@@ -359,7 +359,7 @@
      * This &quot;barging&quot; behavior can be useful in certain
      * circumstances, even though it breaks fairness. If you want to honor
      * the fairness setting, then use
-     * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) }
+     * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS)}
      * which is almost equivalent (it also detects interruption).
      *
      * @return {@code true} if a permit was acquired and {@code false}
@@ -523,7 +523,7 @@
      * &quot;barging&quot; behavior can be useful in certain
      * circumstances, even though it breaks fairness. If you want to
      * honor the fairness setting, then use {@link #tryAcquire(int,
-     * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS) }
+     * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS)}
      * which is almost equivalent (it also detects interruption).
      *
      * @param permits the number of permits to acquire
@@ -631,9 +631,12 @@
     }
 
     /**
-     * Acquires and returns all permits that are immediately available.
+     * Acquires and returns all permits that are immediately
+     * available, or if negative permits are available, releases them.
+     * Upon return, zero permits are available.
      *
-     * @return the number of permits acquired
+     * @return the number of permits acquired or, if negative, the
+     * number released
      */
     public int drainPermits() {
         return sync.drainPermits();
diff --git a/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java b/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java
new file mode 100644
index 0000000..9efb01d
--- /dev/null
+++ b/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java
@@ -0,0 +1,1477 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import static java.util.concurrent.Flow.Publisher;
+import static java.util.concurrent.Flow.Subscriber;
+import static java.util.concurrent.Flow.Subscription;
+
+/**
+ * A {@link Flow.Publisher} that asynchronously issues submitted
+ * (non-null) items to current subscribers until it is closed.  Each
+ * current subscriber receives newly submitted items in the same order
+ * unless drops or exceptions are encountered.  Using a
+ * SubmissionPublisher allows item generators to act as compliant <a
+ * href="http://www.reactive-streams.org/"> reactive-streams</a>
+ * Publishers relying on drop handling and/or blocking for flow
+ * control.
+ *
+ * <p>A SubmissionPublisher uses the {@link Executor} supplied in its
+ * constructor for delivery to subscribers. The best choice of
+ * Executor depends on expected usage. If the generator(s) of
+ * submitted items run in separate threads, and the number of
+ * subscribers can be estimated, consider using a {@link
+ * Executors#newFixedThreadPool}. Otherwise consider using the
+ * default, normally the {@link ForkJoinPool#commonPool}.
+ *
+ * <p>Buffering allows producers and consumers to transiently operate
+ * at different rates.  Each subscriber uses an independent buffer.
+ * Buffers are created upon first use and expanded as needed up to the
+ * given maximum. (The enforced capacity may be rounded up to the
+ * nearest power of two and/or bounded by the largest value supported
+ * by this implementation.)  Invocations of {@link
+ * Flow.Subscription#request(long) request} do not directly result in
+ * buffer expansion, but risk saturation if unfilled requests exceed
+ * the maximum capacity.  The default value of {@link
+ * Flow#defaultBufferSize()} may provide a useful starting point for
+ * choosing a capacity based on expected rates, resources, and usages.
+ *
+ * <p>A single SubmissionPublisher may be shared among multiple
+ * sources. Actions in a source thread prior to publishing an item or
+ * issuing a signal <a href="package-summary.html#MemoryVisibility">
+ * <i>happen-before</i></a> actions subsequent to the corresponding
+ * access by each subscriber. But reported estimates of lag and demand
+ * are designed for use in monitoring, not for synchronization
+ * control, and may reflect stale or inaccurate views of progress.
+ *
+ * <p>Publication methods support different policies about what to do
+ * when buffers are saturated. Method {@link #submit(Object) submit}
+ * blocks until resources are available. This is simplest, but least
+ * responsive.  The {@code offer} methods may drop items (either
+ * immediately or with bounded timeout), but provide an opportunity to
+ * interpose a handler and then retry.
+ *
+ * <p>If any Subscriber method throws an exception, its subscription
+ * is cancelled.  If a handler is supplied as a constructor argument,
+ * it is invoked before cancellation upon an exception in method
+ * {@link Flow.Subscriber#onNext onNext}, but exceptions in methods
+ * {@link Flow.Subscriber#onSubscribe onSubscribe},
+ * {@link Flow.Subscriber#onError(Throwable) onError} and
+ * {@link Flow.Subscriber#onComplete() onComplete} are not recorded or
+ * handled before cancellation.  If the supplied Executor throws
+ * {@link RejectedExecutionException} (or any other RuntimeException
+ * or Error) when attempting to execute a task, or a drop handler
+ * throws an exception when processing a dropped item, then the
+ * exception is rethrown. In these cases, not all subscribers will
+ * have been issued the published item. It is usually good practice to
+ * {@link #closeExceptionally closeExceptionally} in these cases.
+ *
+ * <p>Method {@link #consume(Consumer)} simplifies support for a
+ * common case in which the only action of a subscriber is to request
+ * and process all items using a supplied function.
+ *
+ * <p>This class may also serve as a convenient base for subclasses
+ * that generate items, and use the methods in this class to publish
+ * them.  For example here is a class that periodically publishes the
+ * items generated from a supplier. (In practice you might add methods
+ * to independently start and stop generation, to share Executors
+ * among publishers, and so on, or use a SubmissionPublisher as a
+ * component rather than a superclass.)
+ *
+ * <pre> {@code
+ * class PeriodicPublisher<T> extends SubmissionPublisher<T> {
+ *   final ScheduledFuture<?> periodicTask;
+ *   final ScheduledExecutorService scheduler;
+ *   PeriodicPublisher(Executor executor, int maxBufferCapacity,
+ *                     Supplier<? extends T> supplier,
+ *                     long period, TimeUnit unit) {
+ *     super(executor, maxBufferCapacity);
+ *     scheduler = new ScheduledThreadPoolExecutor(1);
+ *     periodicTask = scheduler.scheduleAtFixedRate(
+ *       () -> submit(supplier.get()), 0, period, unit);
+ *   }
+ *   public void close() {
+ *     periodicTask.cancel(false);
+ *     scheduler.shutdown();
+ *     super.close();
+ *   }
+ * }}</pre>
+ *
+ * <p>Here is an example of a {@link Flow.Processor} implementation.
+ * It uses single-step requests to its publisher for simplicity of
+ * illustration. A more adaptive version could monitor flow using the
+ * lag estimate returned from {@code submit}, along with other utility
+ * methods.
+ *
+ * <pre> {@code
+ * class TransformProcessor<S,T> extends SubmissionPublisher<T>
+ *   implements Flow.Processor<S,T> {
+ *   final Function<? super S, ? extends T> function;
+ *   Flow.Subscription subscription;
+ *   TransformProcessor(Executor executor, int maxBufferCapacity,
+ *                      Function<? super S, ? extends T> function) {
+ *     super(executor, maxBufferCapacity);
+ *     this.function = function;
+ *   }
+ *   public void onSubscribe(Flow.Subscription subscription) {
+ *     (this.subscription = subscription).request(1);
+ *   }
+ *   public void onNext(S item) {
+ *     subscription.request(1);
+ *     submit(function.apply(item));
+ *   }
+ *   public void onError(Throwable ex) { closeExceptionally(ex); }
+ *   public void onComplete() { close(); }
+ * }}</pre>
+ *
+ * @param <T> the published item type
+ * @author Doug Lea
+ * @since 9
+ */
+public class SubmissionPublisher<T> implements Publisher<T>,
+                                               AutoCloseable {
+    /*
+     * Most mechanics are handled by BufferedSubscription. This class
+     * mainly tracks subscribers and ensures sequentiality, by using
+     * built-in synchronization locks across public methods. Using
+     * built-in locks works well in the most typical case in which
+     * only one thread submits items. We extend this idea in
+     * submission methods by detecting single-ownership to reduce
+     * producer-consumer synchronization strength.
+     */
+
+    /** The largest possible power of two array size. */
+    static final int BUFFER_CAPACITY_LIMIT = 1 << 30;
+
+    /**
+     * Initial buffer capacity used when maxBufferCapacity is
+     * greater. Must be a power of two.
+     */
+    static final int INITIAL_CAPACITY = 32;
+
+    /** Round capacity to power of 2, at most limit. */
+    static final int roundCapacity(int cap) {
+        int n = cap - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        return (n <= 0) ? 1 : // at least 1
+            (n >= BUFFER_CAPACITY_LIMIT) ? BUFFER_CAPACITY_LIMIT : n + 1;
+    }
+
+    // default Executor setup; nearly the same as CompletableFuture
+
+    /**
+     * Default executor -- ForkJoinPool.commonPool() unless it cannot
+     * support parallelism.
+     */
+    private static final Executor ASYNC_POOL =
+        (ForkJoinPool.getCommonPoolParallelism() > 1) ?
+        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+    /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+    private static final class ThreadPerTaskExecutor implements Executor {
+        ThreadPerTaskExecutor() {}      // prevent access constructor creation
+        public void execute(Runnable r) { new Thread(r).start(); }
+    }
+
+    /**
+     * Clients (BufferedSubscriptions) are maintained in a linked list
+     * (via their "next" fields). This works well for publish loops.
+     * It requires O(n) traversal to check for duplicate subscribers,
+     * but we expect that subscribing is much less common than
+     * publishing. Unsubscribing occurs only during traversal loops,
+     * when BufferedSubscription methods return negative values
+     * signifying that they have been closed.  To reduce
+     * head-of-line blocking, submit and offer methods first call
+     * BufferedSubscription.offer on each subscriber, and place
+     * saturated ones in retries list (using nextRetry field), and
+     * retry, possibly blocking or dropping.
+     */
+    BufferedSubscription<T> clients;
+
+    /** Run status, updated only within locks */
+    volatile boolean closed;
+    /** Set true on first call to subscribe, to initialize possible owner */
+    boolean subscribed;
+    /** The first caller thread to subscribe, or null if thread ever changed */
+    Thread owner;
+    /** If non-null, the exception in closeExceptionally */
+    volatile Throwable closedException;
+
+    // Parameters for constructing BufferedSubscriptions
+    final Executor executor;
+    final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
+    final int maxBufferCapacity;
+
+    /**
+     * Creates a new SubmissionPublisher using the given Executor for
+     * async delivery to subscribers, with the given maximum buffer size
+     * for each subscriber, and, if non-null, the given handler invoked
+     * when any Subscriber throws an exception in method {@link
+     * Flow.Subscriber#onNext(Object) onNext}.
+     *
+     * @param executor the executor to use for async delivery,
+     * supporting creation of at least one independent thread
+     * @param maxBufferCapacity the maximum capacity for each
+     * subscriber's buffer (the enforced capacity may be rounded up to
+     * the nearest power of two and/or bounded by the largest value
+     * supported by this implementation; method {@link #getMaxBufferCapacity}
+     * returns the actual value)
+     * @param handler if non-null, procedure to invoke upon exception
+     * thrown in method {@code onNext}
+     * @throws NullPointerException if executor is null
+     * @throws IllegalArgumentException if maxBufferCapacity not
+     * positive
+     */
+    public SubmissionPublisher(Executor executor, int maxBufferCapacity,
+                               BiConsumer<? super Subscriber<? super T>, ? super Throwable> handler) {
+        if (executor == null)
+            throw new NullPointerException();
+        if (maxBufferCapacity <= 0)
+            throw new IllegalArgumentException("capacity must be positive");
+        this.executor = executor;
+        this.onNextHandler = handler;
+        this.maxBufferCapacity = roundCapacity(maxBufferCapacity);
+    }
+
+    /**
+     * Creates a new SubmissionPublisher using the given Executor for
+     * async delivery to subscribers, with the given maximum buffer size
+     * for each subscriber, and no handler for Subscriber exceptions in
+     * method {@link Flow.Subscriber#onNext(Object) onNext}.
+     *
+     * @param executor the executor to use for async delivery,
+     * supporting creation of at least one independent thread
+     * @param maxBufferCapacity the maximum capacity for each
+     * subscriber's buffer (the enforced capacity may be rounded up to
+     * the nearest power of two and/or bounded by the largest value
+     * supported by this implementation; method {@link #getMaxBufferCapacity}
+     * returns the actual value)
+     * @throws NullPointerException if executor is null
+     * @throws IllegalArgumentException if maxBufferCapacity not
+     * positive
+     */
+    public SubmissionPublisher(Executor executor, int maxBufferCapacity) {
+        this(executor, maxBufferCapacity, null);
+    }
+
+    /**
+     * Creates a new SubmissionPublisher using the {@link
+     * ForkJoinPool#commonPool()} for async delivery to subscribers
+     * (unless it does not support a parallelism level of at least two,
+     * in which case, a new Thread is created to run each task), with
+     * maximum buffer capacity of {@link Flow#defaultBufferSize}, and no
+     * handler for Subscriber exceptions in method {@link
+     * Flow.Subscriber#onNext(Object) onNext}.
+     */
+    public SubmissionPublisher() {
+        this(ASYNC_POOL, Flow.defaultBufferSize(), null);
+    }
+
+    /**
+     * Adds the given Subscriber unless already subscribed.  If already
+     * subscribed, the Subscriber's {@link
+     * Flow.Subscriber#onError(Throwable) onError} method is invoked on
+     * the existing subscription with an {@link IllegalStateException}.
+     * Otherwise, upon success, the Subscriber's {@link
+     * Flow.Subscriber#onSubscribe onSubscribe} method is invoked
+     * asynchronously with a new {@link Flow.Subscription}.  If {@link
+     * Flow.Subscriber#onSubscribe onSubscribe} throws an exception, the
+     * subscription is cancelled. Otherwise, if this SubmissionPublisher
+     * was closed exceptionally, then the subscriber's {@link
+     * Flow.Subscriber#onError onError} method is invoked with the
+     * corresponding exception, or if closed without exception, the
+     * subscriber's {@link Flow.Subscriber#onComplete() onComplete}
+     * method is invoked.  Subscribers may enable receiving items by
+     * invoking the {@link Flow.Subscription#request(long) request}
+     * method of the new Subscription, and may unsubscribe by invoking
+     * its {@link Flow.Subscription#cancel() cancel} method.
+     *
+     * @param subscriber the subscriber
+     * @throws NullPointerException if subscriber is null
+     */
+    public void subscribe(Subscriber<? super T> subscriber) {
+        if (subscriber == null) throw new NullPointerException();
+        int max = maxBufferCapacity; // allocate initial array
+        Object[] array = new Object[max < INITIAL_CAPACITY ?
+                                    max : INITIAL_CAPACITY];
+        BufferedSubscription<T> subscription =
+            new BufferedSubscription<T>(subscriber, executor, onNextHandler,
+                                        array, max);
+        synchronized (this) {
+            if (!subscribed) {
+                subscribed = true;
+                owner = Thread.currentThread();
+            }
+            for (BufferedSubscription<T> b = clients, pred = null;;) {
+                if (b == null) {
+                    Throwable ex;
+                    subscription.onSubscribe();
+                    if ((ex = closedException) != null)
+                        subscription.onError(ex);
+                    else if (closed)
+                        subscription.onComplete();
+                    else if (pred == null)
+                        clients = subscription;
+                    else
+                        pred.next = subscription;
+                    break;
+                }
+                BufferedSubscription<T> next = b.next;
+                if (b.isClosed()) {   // remove
+                    b.next = null;    // detach
+                    if (pred == null)
+                        clients = next;
+                    else
+                        pred.next = next;
+                }
+                else if (subscriber.equals(b.subscriber)) {
+                    b.onError(new IllegalStateException("Duplicate subscribe"));
+                    break;
+                }
+                else
+                    pred = b;
+                b = next;
+            }
+        }
+    }
+
+    /**
+     * Common implementation for all three forms of submit and offer.
+     * Acts as submit if nanos == Long.MAX_VALUE, else offer.
+     */
+    private int doOffer(T item, long nanos,
+                        BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        if (item == null) throw new NullPointerException();
+        int lag = 0;
+        boolean complete, unowned;
+        synchronized (this) {
+            Thread t = Thread.currentThread(), o;
+            BufferedSubscription<T> b = clients;
+            if ((unowned = ((o = owner) != t)) && o != null)
+                owner = null;                     // disable bias
+            if (b == null)
+                complete = closed;
+            else {
+                complete = false;
+                boolean cleanMe = false;
+                BufferedSubscription<T> retries = null, rtail = null, next;
+                do {
+                    next = b.next;
+                    int stat = b.offer(item, unowned);
+                    if (stat == 0) {              // saturated; add to retry list
+                        b.nextRetry = null;       // avoid garbage on exceptions
+                        if (rtail == null)
+                            retries = b;
+                        else
+                            rtail.nextRetry = b;
+                        rtail = b;
+                    }
+                    else if (stat < 0)            // closed
+                        cleanMe = true;           // remove later
+                    else if (stat > lag)
+                        lag = stat;
+                } while ((b = next) != null);
+
+                if (retries != null || cleanMe)
+                    lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);
+            }
+        }
+        if (complete)
+            throw new IllegalStateException("Closed");
+        else
+            return lag;
+    }
+
+    /**
+     * Helps, (timed) waits for, and/or drops buffers on list; returns
+     * lag or negative drops (for use in offer).
+     */
+    private int retryOffer(T item, long nanos,
+                           BiPredicate<Subscriber<? super T>, ? super T> onDrop,
+                           BufferedSubscription<T> retries, int lag,
+                           boolean cleanMe) {
+        for (BufferedSubscription<T> r = retries; r != null;) {
+            BufferedSubscription<T> nextRetry = r.nextRetry;
+            r.nextRetry = null;
+            if (nanos > 0L)
+                r.awaitSpace(nanos);
+            int stat = r.retryOffer(item);
+            if (stat == 0 && onDrop != null && onDrop.test(r.subscriber, item))
+                stat = r.retryOffer(item);
+            if (stat == 0)
+                lag = (lag >= 0) ? -1 : lag - 1;
+            else if (stat < 0)
+                cleanMe = true;
+            else if (lag >= 0 && stat > lag)
+                lag = stat;
+            r = nextRetry;
+        }
+        if (cleanMe)
+            cleanAndCount();
+        return lag;
+    }
+
+    /**
+     * Returns current list count after removing closed subscribers.
+     * Call only while holding lock.  Used mainly by retryOffer for
+     * cleanup.
+     */
+    private int cleanAndCount() {
+        int count = 0;
+        BufferedSubscription<T> pred = null, next;
+        for (BufferedSubscription<T> b = clients; b != null; b = next) {
+            next = b.next;
+            if (b.isClosed()) {
+                b.next = null;
+                if (pred == null)
+                    clients = next;
+                else
+                    pred.next = next;
+            }
+            else {
+                pred = b;
+                ++count;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Publishes the given item to each current subscriber by
+     * asynchronously invoking its {@link Flow.Subscriber#onNext(Object)
+     * onNext} method, blocking uninterruptibly while resources for any
+     * subscriber are unavailable. This method returns an estimate of
+     * the maximum lag (number of items submitted but not yet consumed)
+     * among all current subscribers. This value is at least one
+     * (accounting for this submitted item) if there are any
+     * subscribers, else zero.
+     *
+     * <p>If the Executor for this publisher throws a
+     * RejectedExecutionException (or any other RuntimeException or
+     * Error) when attempting to asynchronously notify subscribers,
+     * then this exception is rethrown, in which case not all
+     * subscribers will have been issued this item.
+     *
+     * @param item the (non-null) item to publish
+     * @return the estimated maximum lag among subscribers
+     * @throws IllegalStateException if closed
+     * @throws NullPointerException if item is null
+     * @throws RejectedExecutionException if thrown by Executor
+     */
+    public int submit(T item) {
+        return doOffer(item, Long.MAX_VALUE, null);
+    }
+
+    /**
+     * Publishes the given item, if possible, to each current subscriber
+     * by asynchronously invoking its {@link
+     * Flow.Subscriber#onNext(Object) onNext} method. The item may be
+     * dropped by one or more subscribers if resource limits are
+     * exceeded, in which case the given handler (if non-null) is
+     * invoked, and if it returns true, retried once.  Other calls to
+     * methods in this class by other threads are blocked while the
+     * handler is invoked.  Unless recovery is assured, options are
+     * usually limited to logging the error and/or issuing an {@link
+     * Flow.Subscriber#onError(Throwable) onError} signal to the
+     * subscriber.
+     *
+     * <p>This method returns a status indicator: If negative, it
+     * represents the (negative) number of drops (failed attempts to
+     * issue the item to a subscriber). Otherwise it is an estimate of
+     * the maximum lag (number of items submitted but not yet
+     * consumed) among all current subscribers. This value is at least
+     * one (accounting for this submitted item) if there are any
+     * subscribers, else zero.
+     *
+     * <p>If the Executor for this publisher throws a
+     * RejectedExecutionException (or any other RuntimeException or
+     * Error) when attempting to asynchronously notify subscribers, or
+     * the drop handler throws an exception when processing a dropped
+     * item, then this exception is rethrown.
+     *
+     * @param item the (non-null) item to publish
+     * @param onDrop if non-null, the handler invoked upon a drop to a
+     * subscriber, with arguments of the subscriber and item; if it
+     * returns true, an offer is re-attempted (once)
+     * @return if negative, the (negative) number of drops; otherwise
+     * an estimate of maximum lag
+     * @throws IllegalStateException if closed
+     * @throws NullPointerException if item is null
+     * @throws RejectedExecutionException if thrown by Executor
+     */
+    public int offer(T item,
+                     BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        return doOffer(item, 0L, onDrop);
+    }
+
+    /**
+     * Publishes the given item, if possible, to each current subscriber
+     * by asynchronously invoking its {@link
+     * Flow.Subscriber#onNext(Object) onNext} method, blocking while
+     * resources for any subscription are unavailable, up to the
+     * specified timeout or until the caller thread is interrupted, at
+     * which point the given handler (if non-null) is invoked, and if it
+     * returns true, retried once. (The drop handler may distinguish
+     * timeouts from interrupts by checking whether the current thread
+     * is interrupted.)  Other calls to methods in this class by other
+     * threads are blocked while the handler is invoked.  Unless
+     * recovery is assured, options are usually limited to logging the
+     * error and/or issuing an {@link Flow.Subscriber#onError(Throwable)
+     * onError} signal to the subscriber.
+     *
+     * <p>This method returns a status indicator: If negative, it
+     * represents the (negative) number of drops (failed attempts to
+     * issue the item to a subscriber). Otherwise it is an estimate of
+     * the maximum lag (number of items submitted but not yet
+     * consumed) among all current subscribers. This value is at least
+     * one (accounting for this submitted item) if there are any
+     * subscribers, else zero.
+     *
+     * <p>If the Executor for this publisher throws a
+     * RejectedExecutionException (or any other RuntimeException or
+     * Error) when attempting to asynchronously notify subscribers, or
+     * the drop handler throws an exception when processing a dropped
+     * item, then this exception is rethrown.
+     *
+     * @param item the (non-null) item to publish
+     * @param timeout how long to wait for resources for any subscriber
+     * before giving up, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     * {@code timeout} parameter
+     * @param onDrop if non-null, the handler invoked upon a drop to a
+     * subscriber, with arguments of the subscriber and item; if it
+     * returns true, an offer is re-attempted (once)
+     * @return if negative, the (negative) number of drops; otherwise
+     * an estimate of maximum lag
+     * @throws IllegalStateException if closed
+     * @throws NullPointerException if item is null
+     * @throws RejectedExecutionException if thrown by Executor
+     */
+    public int offer(T item, long timeout, TimeUnit unit,
+                     BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        long nanos = unit.toNanos(timeout);
+        // distinguishes from untimed (only wrt interrupt policy)
+        if (nanos == Long.MAX_VALUE) --nanos;
+        return doOffer(item, nanos, onDrop);
+    }
+
+    /**
+     * Unless already closed, issues {@link
+     * Flow.Subscriber#onComplete() onComplete} signals to current
+     * subscribers, and disallows subsequent attempts to publish.
+     * Upon return, this method does <em>NOT</em> guarantee that all
+     * subscribers have yet completed.
+     */
+    public void close() {
+        if (!closed) {
+            BufferedSubscription<T> b;
+            synchronized (this) {
+                // no need to re-check closed here
+                b = clients;
+                clients = null;
+                owner = null;
+                closed = true;
+            }
+            while (b != null) {
+                BufferedSubscription<T> next = b.next;
+                b.next = null;
+                b.onComplete();
+                b = next;
+            }
+        }
+    }
+
+    /**
+     * Unless already closed, issues {@link
+     * Flow.Subscriber#onError(Throwable) onError} signals to current
+     * subscribers with the given error, and disallows subsequent
+     * attempts to publish.  Future subscribers also receive the given
+     * error. Upon return, this method does <em>NOT</em> guarantee
+     * that all subscribers have yet completed.
+     *
+     * @param error the {@code onError} argument sent to subscribers
+     * @throws NullPointerException if error is null
+     */
+    public void closeExceptionally(Throwable error) {
+        if (error == null)
+            throw new NullPointerException();
+        if (!closed) {
+            BufferedSubscription<T> b;
+            synchronized (this) {
+                b = clients;
+                if (!closed) {  // don't clobber racing close
+                    closedException = error;
+                    clients = null;
+                    owner = null;
+                    closed = true;
+                }
+            }
+            while (b != null) {
+                BufferedSubscription<T> next = b.next;
+                b.next = null;
+                b.onError(error);
+                b = next;
+            }
+        }
+    }
+
+    /**
+     * Returns true if this publisher is not accepting submissions.
+     *
+     * @return true if closed
+     */
+    public boolean isClosed() {
+        return closed;
+    }
+
+    /**
+     * Returns the exception associated with {@link
+     * #closeExceptionally(Throwable) closeExceptionally}, or null if
+     * not closed or if closed normally.
+     *
+     * @return the exception, or null if none
+     */
+    public Throwable getClosedException() {
+        return closedException;
+    }
+
+    /**
+     * Returns true if this publisher has any subscribers.
+     *
+     * @return true if this publisher has any subscribers
+     */
+    public boolean hasSubscribers() {
+        boolean nonEmpty = false;
+        synchronized (this) {
+            for (BufferedSubscription<T> b = clients; b != null;) {
+                BufferedSubscription<T> next = b.next;
+                if (b.isClosed()) {
+                    b.next = null;
+                    b = clients = next;
+                }
+                else {
+                    nonEmpty = true;
+                    break;
+                }
+            }
+        }
+        return nonEmpty;
+    }
+
+    /**
+     * Returns the number of current subscribers.
+     *
+     * @return the number of current subscribers
+     */
+    public int getNumberOfSubscribers() {
+        synchronized (this) {
+            return cleanAndCount();
+        }
+    }
+
+    /**
+     * Returns the Executor used for asynchronous delivery.
+     *
+     * @return the Executor used for asynchronous delivery
+     */
+    public Executor getExecutor() {
+        return executor;
+    }
+
+    /**
+     * Returns the maximum per-subscriber buffer capacity.
+     *
+     * @return the maximum per-subscriber buffer capacity
+     */
+    public int getMaxBufferCapacity() {
+        return maxBufferCapacity;
+    }
+
+    /**
+     * Returns a list of current subscribers for monitoring and
+     * tracking purposes, not for invoking {@link Flow.Subscriber}
+     * methods on the subscribers.
+     *
+     * @return list of current subscribers
+     */
+    public List<Subscriber<? super T>> getSubscribers() {
+        ArrayList<Subscriber<? super T>> subs = new ArrayList<>();
+        synchronized (this) {
+            BufferedSubscription<T> pred = null, next;
+            for (BufferedSubscription<T> b = clients; b != null; b = next) {
+                next = b.next;
+                if (b.isClosed()) {
+                    b.next = null;
+                    if (pred == null)
+                        clients = next;
+                    else
+                        pred.next = next;
+                }
+                else {
+                    subs.add(b.subscriber);
+                    pred = b;
+                }
+            }
+        }
+        return subs;
+    }
+
+    /**
+     * Returns true if the given Subscriber is currently subscribed.
+     *
+     * @param subscriber the subscriber
+     * @return true if currently subscribed
+     * @throws NullPointerException if subscriber is null
+     */
+    public boolean isSubscribed(Subscriber<? super T> subscriber) {
+        if (subscriber == null) throw new NullPointerException();
+        if (!closed) {
+            synchronized (this) {
+                BufferedSubscription<T> pred = null, next;
+                for (BufferedSubscription<T> b = clients; b != null; b = next) {
+                    next = b.next;
+                    if (b.isClosed()) {
+                        b.next = null;
+                        if (pred == null)
+                            clients = next;
+                        else
+                            pred.next = next;
+                    }
+                    else if (subscriber.equals(b.subscriber))
+                        return true;
+                    else
+                        pred = b;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns an estimate of the minimum number of items requested
+     * (via {@link Flow.Subscription#request(long) request}) but not
+     * yet produced, among all current subscribers.
+     *
+     * @return the estimate, or zero if no subscribers
+     */
+    public long estimateMinimumDemand() {
+        long min = Long.MAX_VALUE;
+        boolean nonEmpty = false;
+        synchronized (this) {
+            BufferedSubscription<T> pred = null, next;
+            for (BufferedSubscription<T> b = clients; b != null; b = next) {
+                int n; long d;
+                next = b.next;
+                if ((n = b.estimateLag()) < 0) {
+                    b.next = null;
+                    if (pred == null)
+                        clients = next;
+                    else
+                        pred.next = next;
+                }
+                else {
+                    if ((d = b.demand - n) < min)
+                        min = d;
+                    nonEmpty = true;
+                    pred = b;
+                }
+            }
+        }
+        return nonEmpty ? min : 0;
+    }
+
+    /**
+     * Returns an estimate of the maximum number of items produced but
+     * not yet consumed among all current subscribers.
+     *
+     * @return the estimate
+     */
+    public int estimateMaximumLag() {
+        int max = 0;
+        synchronized (this) {
+            BufferedSubscription<T> pred = null, next;
+            for (BufferedSubscription<T> b = clients; b != null; b = next) {
+                int n;
+                next = b.next;
+                if ((n = b.estimateLag()) < 0) {
+                    b.next = null;
+                    if (pred == null)
+                        clients = next;
+                    else
+                        pred.next = next;
+                }
+                else {
+                    if (n > max)
+                        max = n;
+                    pred = b;
+                }
+            }
+        }
+        return max;
+    }
+
+    /**
+     * Processes all published items using the given Consumer function.
+     * Returns a CompletableFuture that is completed normally when this
+     * publisher signals {@link Flow.Subscriber#onComplete()
+     * onComplete}, or completed exceptionally upon any error, or an
+     * exception is thrown by the Consumer, or the returned
+     * CompletableFuture is cancelled, in which case no further items
+     * are processed.
+     *
+     * @param consumer the function applied to each onNext item
+     * @return a CompletableFuture that is completed normally
+     * when the publisher signals onComplete, and exceptionally
+     * upon any error or cancellation
+     * @throws NullPointerException if consumer is null
+     */
+    public CompletableFuture<Void> consume(Consumer<? super T> consumer) {
+        if (consumer == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> status = new CompletableFuture<>();
+        subscribe(new ConsumerSubscriber<T>(status, consumer));
+        return status;
+    }
+
+    /** Subscriber for method consume */
+    static final class ConsumerSubscriber<T> implements Subscriber<T> {
+        final CompletableFuture<Void> status;
+        final Consumer<? super T> consumer;
+        Subscription subscription;
+        ConsumerSubscriber(CompletableFuture<Void> status,
+                           Consumer<? super T> consumer) {
+            this.status = status; this.consumer = consumer;
+        }
+        public final void onSubscribe(Subscription subscription) {
+            this.subscription = subscription;
+            status.whenComplete((v, e) -> subscription.cancel());
+            if (!status.isDone())
+                subscription.request(Long.MAX_VALUE);
+        }
+        public final void onError(Throwable ex) {
+            status.completeExceptionally(ex);
+        }
+        public final void onComplete() {
+            status.complete(null);
+        }
+        public final void onNext(T item) {
+            try {
+                consumer.accept(item);
+            } catch (Throwable ex) {
+                subscription.cancel();
+                status.completeExceptionally(ex);
+            }
+        }
+    }
+
+    /**
+     * A task for consuming buffer items and signals, created and
+     * executed whenever they become available. A task consumes as
+     * many items/signals as possible before terminating, at which
+     * point another task is created when needed. The dual Runnable
+     * and ForkJoinTask declaration saves overhead when executed by
+     * ForkJoinPools, without impacting other kinds of Executors.
+     */
+    @SuppressWarnings("serial")
+    static final class ConsumerTask<T> extends ForkJoinTask<Void>
+        implements Runnable, CompletableFuture.AsynchronousCompletionTask {
+        final BufferedSubscription<T> consumer;
+        ConsumerTask(BufferedSubscription<T> consumer) {
+            this.consumer = consumer;
+        }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { consumer.consume(); return false; }
+        public final void run() { consumer.consume(); }
+    }
+
+    /**
+     * A resizable array-based ring buffer with integrated control to
+     * start a consumer task whenever items are available.  The buffer
+     * algorithm is specialized for the case of at most one concurrent
+     * producer and consumer, and power of two buffer sizes. It relies
+     * primarily on atomic operations (CAS or getAndSet) at the next
+     * array slot to put or take an element, at the "tail" and "head"
+     * indices written only by the producer and consumer respectively.
+     *
+     * We ensure internally that there is at most one active consumer
+     * task at any given time. The publisher guarantees a single
+     * producer via its lock. Sync among producers and consumers
+     * relies on volatile fields "ctl", "demand", and "waiting" (along
+     * with element access). Other variables are accessed in plain
+     * mode, relying on outer ordering and exclusion, and/or enclosing
+     * them within other volatile accesses. Some atomic operations are
+     * avoided by tracking single threaded ownership by producers (in
+     * the style of biased locking).
+     *
+     * Execution control and protocol state are managed using field
+     * "ctl".  Methods to subscribe, close, request, and cancel set
+     * ctl bits (mostly using atomic boolean method getAndBitwiseOr),
+     * and ensure that a task is running. (The corresponding consumer
+     * side actions are in method consume.)  To avoid starting a new
+     * task on each action, ctl also includes a keep-alive bit
+     * (ACTIVE) that is refreshed if needed on producer actions.
+     * (Maintaining agreement about keep-alives requires most atomic
+     * updates to be full SC/Volatile strength, which is still much
+     * cheaper than using one task per item.)  Error signals
+     * additionally null out items and/or fields to reduce termination
+     * latency.  The cancel() method is supported by treating as ERROR
+     * but suppressing onError signal.
+     *
+     * Support for blocking also exploits the fact that there is only
+     * one possible waiter. ManagedBlocker-compatible control fields
+     * are placed in this class itself rather than in wait-nodes.
+     * Blocking control relies on the "waiting" and "waiter"
+     * fields. Producers set them before trying to block. Signalling
+     * unparks and clears fields. If the producer and/or consumer are
+     * using a ForkJoinPool, the producer attempts to help run
+     * consumer tasks via ForkJoinPool.helpAsyncBlocker before
+     * blocking.
+     *
+     * Usages of this class may encounter any of several forms of
+     * memory contention. We try to ameliorate across them without
+     * unduly impacting footprints in low-contention usages where it
+     * isn't needed. Buffer arrays start out small and grow only as
+     * needed.  The class uses @Contended and heuristic field
+     * declaration ordering to reduce false-sharing memory contention
+     * across instances of BufferedSubscription (as in, multiple
+     * subscribers per publisher).  We additionally segregate some
+     * fields that would otherwise nearly always encounter cache line
+     * contention among producers and consumers. To reduce contention
+     * across time (vs space), consumers only periodically update
+     * other fields (see method takeItems), at the expense of possibly
+     * staler reporting of lags and demand (bounded at 12.5% == 1/8
+     * capacity) and possibly more atomic operations.
+     *
+     * Other forms of imbalance and slowdowns can occur during startup
+     * when producer and consumer methods are compiled and/or memory
+     * is allocated at different rates.  This is ameliorated by
+     * artificially subdividing some consumer methods, including
+     * isolation of all subscriber callbacks.  This code also includes
+     * typical power-of-two array screening idioms to avoid compilers
+     * generating traps, along with the usual SSA-based inline
+     * assignment coding style. Also, all methods and fields have
+     * default visibility to simplify usage by callers.
+     */
+    @SuppressWarnings("serial")
+    @jdk.internal.vm.annotation.Contended
+    static final class BufferedSubscription<T>
+        implements Subscription, ForkJoinPool.ManagedBlocker {
+        long timeout;                      // Long.MAX_VALUE if untimed wait
+        int head;                          // next position to take
+        int tail;                          // next position to put
+        final int maxCapacity;             // max buffer size
+        volatile int ctl;                  // atomic run state flags
+        Object[] array;                    // buffer
+        final Subscriber<? super T> subscriber;
+        final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
+        Executor executor;                 // null on error
+        Thread waiter;                     // blocked producer thread
+        Throwable pendingError;            // holds until onError issued
+        BufferedSubscription<T> next;      // used only by publisher
+        BufferedSubscription<T> nextRetry; // used only by publisher
+
+        @jdk.internal.vm.annotation.Contended("c") // segregate
+        volatile long demand;              // # unfilled requests
+        @jdk.internal.vm.annotation.Contended("c")
+        volatile int waiting;              // nonzero if producer blocked
+
+        // ctl bit values
+        static final int CLOSED   = 0x01;  // if set, other bits ignored
+        static final int ACTIVE   = 0x02;  // keep-alive for consumer task
+        static final int REQS     = 0x04;  // (possibly) nonzero demand
+        static final int ERROR    = 0x08;  // issues onError when noticed
+        static final int COMPLETE = 0x10;  // issues onComplete when done
+        static final int RUN      = 0x20;  // task is or will be running
+        static final int OPEN     = 0x40;  // true after subscribe
+
+        static final long INTERRUPTED = -1L; // timeout vs interrupt sentinel
+
+        BufferedSubscription(Subscriber<? super T> subscriber,
+                             Executor executor,
+                             BiConsumer<? super Subscriber<? super T>,
+                             ? super Throwable> onNextHandler,
+                             Object[] array,
+                             int maxBufferCapacity) {
+            this.subscriber = subscriber;
+            this.executor = executor;
+            this.onNextHandler = onNextHandler;
+            this.array = array;
+            this.maxCapacity = maxBufferCapacity;
+        }
+
+        // Wrappers for some VarHandle methods
+
+        final boolean weakCasCtl(int cmp, int val) {
+            return CTL.weakCompareAndSet(this, cmp, val);
+        }
+
+        final int getAndBitwiseOrCtl(int bits) {
+            return (int)CTL.getAndBitwiseOr(this, bits);
+        }
+
+        final long subtractDemand(int k) {
+            long n = (long)(-k);
+            return n + (long)DEMAND.getAndAdd(this, n);
+        }
+
+        final boolean casDemand(long cmp, long val) {
+            return DEMAND.compareAndSet(this, cmp, val);
+        }
+
+        // Utilities used by SubmissionPublisher
+
+        /**
+         * Returns true if closed (consumer task may still be running).
+         */
+        final boolean isClosed() {
+            return (ctl & CLOSED) != 0;
+        }
+
+        /**
+         * Returns estimated number of buffered items, or negative if
+         * closed.
+         */
+        final int estimateLag() {
+            int c = ctl, n = tail - head;
+            return ((c & CLOSED) != 0) ? -1 : (n < 0) ? 0 : n;
+        }
+
+        // Methods for submitting items
+
+        /**
+         * Tries to add item and start consumer task if necessary.
+         * @return negative if closed, 0 if saturated, else estimated lag
+         */
+        final int offer(T item, boolean unowned) {
+            Object[] a;
+            int stat = 0, cap = ((a = array) == null) ? 0 : a.length;
+            int t = tail, i = t & (cap - 1), n = t + 1 - head;
+            if (cap > 0) {
+                boolean added;
+                if (n >= cap && cap < maxCapacity) // resize
+                    added = growAndOffer(item, a, t);
+                else if (n >= cap || unowned)      // need volatile CAS
+                    added = QA.compareAndSet(a, i, null, item);
+                else {                             // can use release mode
+                    QA.setRelease(a, i, item);
+                    added = true;
+                }
+                if (added) {
+                    tail = t + 1;
+                    stat = n;
+                }
+            }
+            return startOnOffer(stat);
+        }
+
+        /**
+         * Tries to expand buffer and add item, returning true on
+         * success. Currently fails only if out of memory.
+         */
+        final boolean growAndOffer(T item, Object[] a, int t) {
+            int cap = 0, newCap = 0;
+            Object[] newArray = null;
+            if (a != null && (cap = a.length) > 0 && (newCap = cap << 1) > 0) {
+                try {
+                    newArray = new Object[newCap];
+                } catch (OutOfMemoryError ex) {
+                }
+            }
+            if (newArray == null)
+                return false;
+            else {                                // take and move items
+                int newMask = newCap - 1;
+                newArray[t-- & newMask] = item;
+                for (int mask = cap - 1, k = mask; k >= 0; --k) {
+                    Object x = QA.getAndSet(a, t & mask, null);
+                    if (x == null)
+                        break;                    // already consumed
+                    else
+                        newArray[t-- & newMask] = x;
+                }
+                array = newArray;
+                VarHandle.releaseFence();         // release array and slots
+                return true;
+            }
+        }
+
+        /**
+         * Version of offer for retries (no resize or bias)
+         */
+        final int retryOffer(T item) {
+            Object[] a;
+            int stat = 0, t = tail, h = head, cap;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                QA.compareAndSet(a, (cap - 1) & t, null, item))
+                stat = (tail = t + 1) - h;
+            return startOnOffer(stat);
+        }
+
+        /**
+         * Tries to start consumer task after offer.
+         * @return negative if now closed, else argument
+         */
+        final int startOnOffer(int stat) {
+            int c; // start or keep alive if requests exist and not active
+            if (((c = ctl) & (REQS | ACTIVE)) == REQS &&
+                ((c = getAndBitwiseOrCtl(RUN | ACTIVE)) & (RUN | CLOSED)) == 0)
+                tryStart();
+            else if ((c & CLOSED) != 0)
+                stat = -1;
+            return stat;
+        }
+
+        /**
+         * Tries to start consumer task. Sets error state on failure.
+         */
+        final void tryStart() {
+            try {
+                Executor e;
+                ConsumerTask<T> task = new ConsumerTask<T>(this);
+                if ((e = executor) != null)   // skip if disabled on error
+                    e.execute(task);
+            } catch (RuntimeException | Error ex) {
+                getAndBitwiseOrCtl(ERROR | CLOSED);
+                throw ex;
+            }
+        }
+
+        // Signals to consumer tasks
+
+        /**
+         * Sets the given control bits, starting task if not running or closed.
+         * @param bits state bits, assumed to include RUN but not CLOSED
+         */
+        final void startOnSignal(int bits) {
+            if ((ctl & bits) != bits &&
+                (getAndBitwiseOrCtl(bits) & (RUN | CLOSED)) == 0)
+                tryStart();
+        }
+
+        final void onSubscribe() {
+            startOnSignal(RUN | ACTIVE);
+        }
+
+        final void onComplete() {
+            startOnSignal(RUN | ACTIVE | COMPLETE);
+        }
+
+        final void onError(Throwable ex) {
+            int c; Object[] a;      // to null out buffer on async error
+            if (ex != null)
+                pendingError = ex;  // races are OK
+            if (((c = getAndBitwiseOrCtl(ERROR | RUN | ACTIVE)) & CLOSED) == 0) {
+                if ((c & RUN) == 0)
+                    tryStart();
+                else if ((a = array) != null)
+                    Arrays.fill(a, null);
+            }
+        }
+
+        public final void cancel() {
+            onError(null);
+        }
+
+        public final void request(long n) {
+            if (n > 0L) {
+                for (;;) {
+                    long p = demand, d = p + n;  // saturate
+                    if (casDemand(p, d < p ? Long.MAX_VALUE : d))
+                        break;
+                }
+                startOnSignal(RUN | ACTIVE | REQS);
+            }
+            else
+                onError(new IllegalArgumentException(
+                            "non-positive subscription request"));
+        }
+
+        // Consumer task actions
+
+        /**
+         * Consumer loop, called from ConsumerTask, or indirectly when
+         * helping during submit.
+         */
+        final void consume() {
+            Subscriber<? super T> s;
+            if ((s = subscriber) != null) {          // hoist checks
+                subscribeOnOpen(s);
+                long d = demand;
+                for (int h = head, t = tail;;) {
+                    int c, taken; boolean empty;
+                    if (((c = ctl) & ERROR) != 0) {
+                        closeOnError(s, null);
+                        break;
+                    }
+                    else if ((taken = takeItems(s, d, h)) > 0) {
+                        head = h += taken;
+                        d = subtractDemand(taken);
+                    }
+                    else if ((d = demand) == 0L && (c & REQS) != 0)
+                        weakCasCtl(c, c & ~REQS);    // exhausted demand
+                    else if (d != 0L && (c & REQS) == 0)
+                        weakCasCtl(c, c | REQS);     // new demand
+                    else if (t == (t = tail)) {      // stability check
+                        if ((empty = (t == h)) && (c & COMPLETE) != 0) {
+                            closeOnComplete(s);      // end of stream
+                            break;
+                        }
+                        else if (empty || d == 0L) {
+                            int bit = ((c & ACTIVE) != 0) ? ACTIVE : RUN;
+                            if (weakCasCtl(c, c & ~bit) && bit == RUN)
+                                break;               // un-keep-alive or exit
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Consumes some items until unavailable or bound or error.
+         *
+         * @param s subscriber
+         * @param d current demand
+         * @param h current head
+         * @return number taken
+         */
+        final int takeItems(Subscriber<? super T> s, long d, int h) {
+            Object[] a;
+            int k = 0, cap;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                int m = cap - 1, b = (m >>> 3) + 1; // min(1, cap/8)
+                int n = (d < (long)b) ? (int)d : b;
+                for (; k < n; ++h, ++k) {
+                    Object x = QA.getAndSet(a, h & m, null);
+                    if (waiting != 0)
+                        signalWaiter();
+                    if (x == null)
+                        break;
+                    else if (!consumeNext(s, x))
+                        break;
+                }
+            }
+            return k;
+        }
+
+        final boolean consumeNext(Subscriber<? super T> s, Object x) {
+            try {
+                @SuppressWarnings("unchecked") T y = (T) x;
+                if (s != null)
+                    s.onNext(y);
+                return true;
+            } catch (Throwable ex) {
+                handleOnNext(s, ex);
+                return false;
+            }
+        }
+
+        /**
+         * Processes exception in Subscriber.onNext.
+         */
+        final void handleOnNext(Subscriber<? super T> s, Throwable ex) {
+            BiConsumer<? super Subscriber<? super T>, ? super Throwable> h;
+            try {
+                if ((h = onNextHandler) != null)
+                    h.accept(s, ex);
+            } catch (Throwable ignore) {
+            }
+            closeOnError(s, ex);
+        }
+
+        /**
+         * Issues subscriber.onSubscribe if this is first signal.
+         */
+        final void subscribeOnOpen(Subscriber<? super T> s) {
+            if ((ctl & OPEN) == 0 && (getAndBitwiseOrCtl(OPEN) & OPEN) == 0)
+                consumeSubscribe(s);
+        }
+
+        final void consumeSubscribe(Subscriber<? super T> s) {
+            try {
+                if (s != null) // ignore if disabled
+                    s.onSubscribe(this);
+            } catch (Throwable ex) {
+                closeOnError(s, ex);
+            }
+        }
+
+        /**
+         * Issues subscriber.onComplete unless already closed.
+         */
+        final void closeOnComplete(Subscriber<? super T> s) {
+            if ((getAndBitwiseOrCtl(CLOSED) & CLOSED) == 0)
+                consumeComplete(s);
+        }
+
+        final void consumeComplete(Subscriber<? super T> s) {
+            try {
+                if (s != null)
+                    s.onComplete();
+            } catch (Throwable ignore) {
+            }
+        }
+
+        /**
+         * Issues subscriber.onError, and unblocks producer if needed.
+         */
+        final void closeOnError(Subscriber<? super T> s, Throwable ex) {
+            if ((getAndBitwiseOrCtl(ERROR | CLOSED) & CLOSED) == 0) {
+                if (ex == null)
+                    ex = pendingError;
+                pendingError = null;  // detach
+                executor = null;      // suppress racing start calls
+                signalWaiter();
+                consumeError(s, ex);
+            }
+        }
+
+        final void consumeError(Subscriber<? super T> s, Throwable ex) {
+            try {
+                if (ex != null && s != null)
+                    s.onError(ex);
+            } catch (Throwable ignore) {
+            }
+        }
+
+        // Blocking support
+
+        /**
+         * Unblocks waiting producer.
+         */
+        final void signalWaiter() {
+            Thread w;
+            waiting = 0;
+            if ((w = waiter) != null)
+                LockSupport.unpark(w);
+        }
+
+        /**
+         * Returns true if closed or space available.
+         * For ManagedBlocker.
+         */
+        public final boolean isReleasable() {
+            Object[] a; int cap;
+            return ((ctl & CLOSED) != 0 ||
+                    ((a = array) != null && (cap = a.length) > 0 &&
+                     QA.getAcquire(a, (cap - 1) & tail) == null));
+        }
+
+        /**
+         * Helps or blocks until timeout, closed, or space available.
+         */
+        final void awaitSpace(long nanos) {
+            if (!isReleasable()) {
+                ForkJoinPool.helpAsyncBlocker(executor, this);
+                if (!isReleasable()) {
+                    timeout = nanos;
+                    try {
+                        ForkJoinPool.managedBlock(this);
+                    } catch (InterruptedException ie) {
+                        timeout = INTERRUPTED;
+                    }
+                    if (timeout == INTERRUPTED)
+                        Thread.currentThread().interrupt();
+                }
+            }
+        }
+
+        /**
+         * Blocks until closed, space available or timeout.
+         * For ManagedBlocker.
+         */
+        public final boolean block() {
+            long nanos = timeout;
+            boolean timed = (nanos < Long.MAX_VALUE);
+            long deadline = timed ? System.nanoTime() + nanos : 0L;
+            while (!isReleasable()) {
+                if (Thread.interrupted()) {
+                    timeout = INTERRUPTED;
+                    if (timed)
+                        break;
+                }
+                else if (timed && (nanos = deadline - System.nanoTime()) <= 0L)
+                    break;
+                else if (waiter == null)
+                    waiter = Thread.currentThread();
+                else if (waiting == 0)
+                    waiting = 1;
+                else if (timed)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    LockSupport.park(this);
+            }
+            waiter = null;
+            waiting = 0;
+            return true;
+        }
+
+        // VarHandle mechanics
+        static final VarHandle CTL;
+        static final VarHandle DEMAND;
+        static final VarHandle QA;
+
+        static {
+            try {
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                CTL = l.findVarHandle(BufferedSubscription.class, "ctl",
+                                      int.class);
+                DEMAND = l.findVarHandle(BufferedSubscription.class, "demand",
+                                         long.class);
+                QA = MethodHandles.arrayElementVarHandle(Object[].class);
+            } catch (ReflectiveOperationException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+
+            // Reduce the risk of rare disastrous classloading in first call to
+            // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+            Class<?> ensureLoaded = LockSupport.class;
+        }
+    }
+}
diff --git a/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java b/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
index 9655205..d15c3b5 100644
--- a/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
@@ -36,19 +36,18 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.Objects;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.concurrent.locks.LockSupport;
 import java.util.concurrent.locks.ReentrantLock;
 
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
 /**
  * A {@linkplain BlockingQueue blocking queue} in which each insert
  * operation must wait for a corresponding remove operation by another
@@ -77,9 +76,12 @@
  * is not guaranteed. However, a queue constructed with fairness set
  * to {@code true} grants threads access in FIFO order.
  *
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
  *
  * @since 1.5
  * @author Doug Lea and Bill Scherer and Michael Scott
@@ -247,7 +249,7 @@
 
             boolean casNext(SNode cmp, SNode val) {
                 return cmp == next &&
-                    U.compareAndSwapObject(this, NEXT, cmp, val);
+                    SNEXT.compareAndSet(this, cmp, val);
             }
 
             /**
@@ -260,7 +262,7 @@
              */
             boolean tryMatch(SNode s) {
                 if (match == null &&
-                    U.compareAndSwapObject(this, MATCH, null, s)) {
+                    SMATCH.compareAndSet(this, null, s)) {
                     Thread w = waiter;
                     if (w != null) {    // waiters need at most one unpark
                         waiter = null;
@@ -275,26 +277,23 @@
              * Tries to cancel a wait by matching node to itself.
              */
             void tryCancel() {
-                U.compareAndSwapObject(this, MATCH, null, this);
+                SMATCH.compareAndSet(this, null, this);
             }
 
             boolean isCancelled() {
                 return match == this;
             }
 
-            // Unsafe mechanics
-            private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-            private static final long MATCH;
-            private static final long NEXT;
-
+            // VarHandle mechanics
+            private static final VarHandle SMATCH;
+            private static final VarHandle SNEXT;
             static {
                 try {
-                    MATCH = U.objectFieldOffset
-                        (SNode.class.getDeclaredField("match"));
-                    NEXT = U.objectFieldOffset
-                        (SNode.class.getDeclaredField("next"));
+                    MethodHandles.Lookup l = MethodHandles.lookup();
+                    SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
+                    SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
                 } catch (ReflectiveOperationException e) {
-                    throw new Error(e);
+                    throw new ExceptionInInitializerError(e);
                 }
             }
         }
@@ -304,7 +303,7 @@
 
         boolean casHead(SNode h, SNode nh) {
             return h == head &&
-                U.compareAndSwapObject(this, HEAD, h, nh);
+                SHEAD.compareAndSet(this, h, nh);
         }
 
         /**
@@ -451,8 +450,11 @@
                         continue;
                     }
                 }
-                if (spins > 0)
+                if (spins > 0) {
+                    // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+                    // Thread.onSpinWait();
                     spins = shouldSpin(s) ? (spins - 1) : 0;
+                }
                 else if (s.waiter == null)
                     s.waiter = w; // establish waiter so can park next iter
                 else if (!timed)
@@ -508,15 +510,14 @@
             }
         }
 
-        // Unsafe mechanics
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-        private static final long HEAD;
+        // VarHandle mechanics
+        private static final VarHandle SHEAD;
         static {
             try {
-                HEAD = U.objectFieldOffset
-                    (TransferStack.class.getDeclaredField("head"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
         }
     }
@@ -546,19 +547,19 @@
 
             boolean casNext(QNode cmp, QNode val) {
                 return next == cmp &&
-                    U.compareAndSwapObject(this, NEXT, cmp, val);
+                    QNEXT.compareAndSet(this, cmp, val);
             }
 
             boolean casItem(Object cmp, Object val) {
                 return item == cmp &&
-                    U.compareAndSwapObject(this, ITEM, cmp, val);
+                    QITEM.compareAndSet(this, cmp, val);
             }
 
             /**
              * Tries to cancel by CAS'ing ref to this as item.
              */
             void tryCancel(Object cmp) {
-                U.compareAndSwapObject(this, ITEM, cmp, this);
+                QITEM.compareAndSet(this, cmp, this);
             }
 
             boolean isCancelled() {
@@ -574,19 +575,16 @@
                 return next == this;
             }
 
-            // Unsafe mechanics
-            private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-            private static final long ITEM;
-            private static final long NEXT;
-
+            // VarHandle mechanics
+            private static final VarHandle QITEM;
+            private static final VarHandle QNEXT;
             static {
                 try {
-                    ITEM = U.objectFieldOffset
-                        (QNode.class.getDeclaredField("item"));
-                    NEXT = U.objectFieldOffset
-                        (QNode.class.getDeclaredField("next"));
+                    MethodHandles.Lookup l = MethodHandles.lookup();
+                    QITEM = l.findVarHandle(QNode.class, "item", Object.class);
+                    QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
                 } catch (ReflectiveOperationException e) {
-                    throw new Error(e);
+                    throw new ExceptionInInitializerError(e);
                 }
             }
         }
@@ -614,7 +612,7 @@
          */
         void advanceHead(QNode h, QNode nh) {
             if (h == head &&
-                U.compareAndSwapObject(this, HEAD, h, nh))
+                QHEAD.compareAndSet(this, h, nh))
                 h.next = h; // forget old next
         }
 
@@ -623,7 +621,7 @@
          */
         void advanceTail(QNode t, QNode nt) {
             if (tail == t)
-                U.compareAndSwapObject(this, TAIL, t, nt);
+                QTAIL.compareAndSet(this, t, nt);
         }
 
         /**
@@ -631,7 +629,7 @@
          */
         boolean casCleanMe(QNode cmp, QNode val) {
             return cleanMe == cmp &&
-                U.compareAndSwapObject(this, CLEANME, cmp, val);
+                QCLEANME.compareAndSet(this, cmp, val);
         }
 
         /**
@@ -752,8 +750,11 @@
                         continue;
                     }
                 }
-                if (spins > 0)
+                if (spins > 0) {
                     --spins;
+                    // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+                    // Thread.onSpinWait();
+                }
                 else if (s.waiter == null)
                     s.waiter = w;
                 else if (!timed)
@@ -817,20 +818,21 @@
             }
         }
 
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-        private static final long HEAD;
-        private static final long TAIL;
-        private static final long CLEANME;
+        // VarHandle mechanics
+        private static final VarHandle QHEAD;
+        private static final VarHandle QTAIL;
+        private static final VarHandle QCLEANME;
         static {
             try {
-                HEAD = U.objectFieldOffset
-                    (TransferQueue.class.getDeclaredField("head"));
-                TAIL = U.objectFieldOffset
-                    (TransferQueue.class.getDeclaredField("tail"));
-                CLEANME = U.objectFieldOffset
-                    (TransferQueue.class.getDeclaredField("cleanMe"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                QHEAD = l.findVarHandle(TransferQueue.class, "head",
+                                        QNode.class);
+                QTAIL = l.findVarHandle(TransferQueue.class, "tail",
+                                        QNode.class);
+                QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
+                                           QNode.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
         }
     }
@@ -1066,7 +1068,7 @@
 
     /**
      * Returns an empty spliterator in which calls to
-     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     * {@link Spliterator#trySplit() trySplit} always return {@code null}.
      *
      * @return an empty spliterator
      * @since 1.8
@@ -1112,15 +1114,12 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c) {
-        if (c == null)
-            throw new NullPointerException();
+        Objects.requireNonNull(c);
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        for (E e; (e = poll()) != null;) {
+        for (E e; (e = poll()) != null; n++)
             c.add(e);
-            ++n;
-        }
         return n;
     }
 
@@ -1131,15 +1130,12 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c, int maxElements) {
-        if (c == null)
-            throw new NullPointerException();
+        Objects.requireNonNull(c);
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        for (E e; n < maxElements && (e = poll()) != null;) {
+        for (E e; n < maxElements && (e = poll()) != null; n++)
             c.add(e);
-            ++n;
-        }
         return n;
     }
 
diff --git a/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
index 195f8ac..c20d2b3 100644
--- a/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
+++ b/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -36,6 +36,7 @@
 package java.util.concurrent;
 
 import java.io.ObjectStreamField;
+import java.security.AccessControlContext;
 import java.util.Random;
 import java.util.Spliterator;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -47,6 +48,8 @@
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
 import java.util.stream.StreamSupport;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.misc.VM;
 
 /**
  * A random number generator isolated to the current thread.  Like the
@@ -64,7 +67,7 @@
  * {@code ThreadLocalRandom.current().nextX(...)} (where
  * {@code X} is {@code Int}, {@code Long}, etc).
  * When all usages are of this form, it is never possible to
- * accidently share a {@code ThreadLocalRandom} across multiple threads.
+ * accidentally share a {@code ThreadLocalRandom} across multiple threads.
  *
  * <p>This class also provides additional commonly used bounded random
  * generation methods.
@@ -95,7 +98,9 @@
      * ThreadLocalRandom sequence.  The dual use is a marriage of
      * convenience, but is a simple and efficient way of reducing
      * application-level overhead and footprint of most concurrent
-     * programs.
+     * programs. Even more opportunistically, we also define here
+     * other package-private utilities that access Thread class
+     * fields.
      *
      * Even though this class subclasses java.util.Random, it uses the
      * same basic algorithm as java.util.SplittableRandom.  (See its
@@ -193,9 +198,17 @@
         return r;
     }
 
-    // We must define this, but never use it.
+    /**
+     * Generates a pseudorandom number with the indicated number of
+     * low-order bits.  Because this class has no subclasses, this
+     * method cannot be invoked or overridden.
+     *
+     * @param  bits random bits
+     * @return the next pseudorandom value from this random number
+     *         generator's sequence
+     */
     protected int next(int bits) {
-        return (int)(mix64(nextSeed()) >>> (64 - bits));
+        return nextInt() >>> (32 - bits);
     }
 
     /**
@@ -455,7 +468,7 @@
             s = v1 * v1 + v2 * v2;
         } while (s >= 1 || s == 0);
         double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
-        nextLocalGaussian.set(new Double(v2 * multiplier));
+        nextLocalGaussian.set(Double.valueOf(v2 * multiplier));
         return v1 * multiplier;
     }
 
@@ -687,8 +700,7 @@
      * @return a stream of pseudorandom {@code double} values,
      *         each with the given origin (inclusive) and bound (exclusive)
      * @throws IllegalArgumentException if {@code streamSize} is
-     *         less than zero
-     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         less than zero, or {@code randomNumberOrigin}
      *         is greater than or equal to {@code randomNumberBound}
      * @since 1.8
      */
@@ -958,6 +970,21 @@
         return r;
     }
 
+    // Support for other package-private ThreadLocal access
+
+    /**
+     * Erases ThreadLocals by nulling out Thread maps.
+     */
+    static final void eraseThreadLocals(Thread thread) {
+        U.putObject(thread, THREADLOCALS, null);
+        U.putObject(thread, INHERITABLETHREADLOCALS, null);
+    }
+
+    static final void setInheritedAccessControlContext(Thread thread,
+                                                       AccessControlContext acc) {
+        U.putObjectRelease(thread, INHERITEDACCESSCONTROLCONTEXT, acc);
+    }
+
     // Serialization support
 
     private static final long serialVersionUID = -5851777807851030925L;
@@ -1012,7 +1039,10 @@
      */
     private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
 
-    // Constants from SplittableRandom
+    /**
+     * The least non-zero value returned by nextDouble(). This value
+     * is scaled by a random value of 53 bits to produce a result.
+     */
     private static final double DOUBLE_UNIT = 0x1.0p-53;  // 1.0  / (1L << 53)
     private static final float  FLOAT_UNIT  = 0x1.0p-24f; // 1.0f / (1 << 24)
 
@@ -1022,22 +1052,19 @@
     static final String BAD_SIZE  = "size must be non-negative";
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long SEED;
-    private static final long PROBE;
-    private static final long SECONDARY;
-    static {
-        try {
-            SEED = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocalRandomSeed"));
-            PROBE = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocalRandomProbe"));
-            SECONDARY = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
-        } catch (ReflectiveOperationException e) {
-            throw new Error(e);
-        }
-    }
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long SEED = U.objectFieldOffset
+            (Thread.class, "threadLocalRandomSeed");
+    private static final long PROBE = U.objectFieldOffset
+            (Thread.class, "threadLocalRandomProbe");
+    private static final long SECONDARY = U.objectFieldOffset
+            (Thread.class, "threadLocalRandomSecondarySeed");
+    private static final long THREADLOCALS = U.objectFieldOffset
+            (Thread.class, "threadLocals");
+    private static final long INHERITABLETHREADLOCALS = U.objectFieldOffset
+            (Thread.class, "inheritableThreadLocals");
+    private static final long INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
+            (Thread.class, "inheritedAccessControlContext");
 
     /** Rarely-used holder for the second of a pair of Gaussians */
     private static final ThreadLocal<Double> nextLocalGaussian =
@@ -1058,11 +1085,8 @@
 
     // at end of <clinit> to survive static initialization circularity
     static {
-        if (java.security.AccessController.doPrivileged(
-            new java.security.PrivilegedAction<Boolean>() {
-                public Boolean run() {
-                    return Boolean.getBoolean("java.util.secureRandomSeed");
-                }})) {
+        String sec = VM.getSavedProperty("java.util.secureRandomSeed");
+        if (Boolean.parseBoolean(sec)) {
             byte[] seedBytes = java.security.SecureRandom.getSeed(8);
             long s = (long)seedBytes[0] & 0xffL;
             for (int i = 1; i < 8; ++i)
diff --git a/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
index b0096a4..f88242b 100644
--- a/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
+++ b/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
@@ -79,31 +79,28 @@
  *
  * <dt>Core and maximum pool sizes</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * A {@code ThreadPoolExecutor} will automatically adjust the
+ * <dd>A {@code ThreadPoolExecutor} will automatically adjust the
  * pool size (see {@link #getPoolSize})
  * according to the bounds set by
  * corePoolSize (see {@link #getCorePoolSize}) and
  * maximumPoolSize (see {@link #getMaximumPoolSize}).
  *
  * When a new task is submitted in method {@link #execute(Runnable)},
- * and fewer than corePoolSize threads are running, a new thread is
+ * if fewer than corePoolSize threads are running, a new thread is
  * created to handle the request, even if other worker threads are
- * idle.  If there are more than corePoolSize but less than
- * maximumPoolSize threads running, a new thread will be created only
- * if the queue is full.  By setting corePoolSize and maximumPoolSize
- * the same, you create a fixed-size thread pool. By setting
- * maximumPoolSize to an essentially unbounded value such as {@code
- * Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary
- * number of concurrent tasks. Most typically, core and maximum pool
- * sizes are set only upon construction, but they may also be changed
- * dynamically using {@link #setCorePoolSize} and {@link
- * #setMaximumPoolSize}. </dd>
+ * idle.  Else if fewer than maximumPoolSize threads are running, a
+ * new thread will be created to handle the request only if the queue
+ * is full.  By setting corePoolSize and maximumPoolSize the same, you
+ * create a fixed-size thread pool. By setting maximumPoolSize to an
+ * essentially unbounded value such as {@code Integer.MAX_VALUE}, you
+ * allow the pool to accommodate an arbitrary number of concurrent
+ * tasks. Most typically, core and maximum pool sizes are set only
+ * upon construction, but they may also be changed dynamically using
+ * {@link #setCorePoolSize} and {@link #setMaximumPoolSize}. </dd>
  *
  * <dt>On-demand construction</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * By default, even core threads are initially created and
+ * <dd>By default, even core threads are initially created and
  * started only when new tasks arrive, but this can be overridden
  * dynamically using method {@link #prestartCoreThread} or {@link
  * #prestartAllCoreThreads}.  You probably want to prestart threads if
@@ -111,8 +108,7 @@
  *
  * <dt>Creating new threads</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * New threads are created using a {@link ThreadFactory}.  If not
+ * <dd>New threads are created using a {@link ThreadFactory}.  If not
  * otherwise specified, a {@link Executors#defaultThreadFactory} is
  * used, that creates threads to all be in the same {@link
  * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
@@ -129,8 +125,7 @@
  *
  * <dt>Keep-alive times</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * If the pool currently has more than corePoolSize threads,
+ * <dd>If the pool currently has more than corePoolSize threads,
  * excess threads will be terminated if they have been idle for more
  * than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
  * This provides a means of reducing resource consumption when the
@@ -147,8 +142,7 @@
  *
  * <dt>Queuing</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * Any {@link BlockingQueue} may be used to transfer and hold
+ * <dd>Any {@link BlockingQueue} may be used to transfer and hold
  * submitted tasks.  The use of this queue interacts with pool sizing:
  *
  * <ul>
@@ -213,8 +207,7 @@
  *
  * <dt>Rejected tasks</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * New tasks submitted in method {@link #execute(Runnable)} will be
+ * <dd>New tasks submitted in method {@link #execute(Runnable)} will be
  * <em>rejected</em> when the Executor has been shut down, and also when
  * the Executor uses finite bounds for both maximum threads and work queue
  * capacity, and is saturated.  In either case, the {@code execute} method
@@ -225,9 +218,8 @@
  *
  * <ol>
  *
- * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the
- * handler throws a runtime {@link RejectedExecutionException} upon
- * rejection.
+ * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the handler
+ * throws a runtime {@link RejectedExecutionException} upon rejection.
  *
  * <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
  * that invokes {@code execute} itself runs the task. This provides a
@@ -251,8 +243,7 @@
  *
  * <dt>Hook methods</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * This class provides {@code protected} overridable
+ * <dd>This class provides {@code protected} overridable
  * {@link #beforeExecute(Thread, Runnable)} and
  * {@link #afterExecute(Runnable, Throwable)} methods that are called
  * before and after execution of each task.  These can be used to
@@ -268,22 +259,19 @@
  *
  * <dt>Queue maintenance</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * Method {@link #getQueue()} allows access to the work queue
+ * <dd>Method {@link #getQueue()} allows access to the work queue
  * for purposes of monitoring and debugging.  Use of this method for
  * any other purpose is strongly discouraged.  Two supplied methods,
  * {@link #remove(Runnable)} and {@link #purge} are available to
  * assist in storage reclamation when large numbers of queued tasks
  * become cancelled.</dd>
  *
- * <dt>Finalization</dt>
+ * <dt>Reclamation</dt>
  *
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * A pool that is no longer referenced in a program <em>AND</em>
- * has no remaining threads will be {@code shutdown} automatically. If
- * you would like to ensure that unreferenced pools are reclaimed even
- * if users forget to call {@link #shutdown}, then you must arrange
- * that unused threads eventually die, by setting appropriate
+ * <dd>A pool that is no longer referenced in a program <em>AND</em>
+ * has no remaining threads may be reclaimed (garbage collected)
+ * without being explicitly shutdown. You can configure a pool to
+ * allow all unused threads to eventually die by setting appropriate
  * keep-alive times, using a lower bound of zero core threads and/or
  * setting {@link #allowCoreThreadTimeOut(boolean)}.  </dd>
  *
@@ -374,7 +362,7 @@
      * time, but need not hit each state. The transitions are:
      *
      * RUNNING -> SHUTDOWN
-     *    On invocation of shutdown(), perhaps implicitly in finalize()
+     *    On invocation of shutdown()
      * (RUNNING or SHUTDOWN) -> STOP
      *    On invocation of shutdownNow()
      * SHUTDOWN -> TIDYING
@@ -398,7 +386,7 @@
     @ReachabilitySensitive
     private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
     private static final int COUNT_BITS = Integer.SIZE - 3;
-    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
+    private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
 
     // runState is stored in the high-order bits
     private static final int RUNNING    = -1 << COUNT_BITS;
@@ -408,8 +396,8 @@
     private static final int TERMINATED =  3 << COUNT_BITS;
 
     // Packing and unpacking ctl
-    private static int runStateOf(int c)     { return c & ~CAPACITY; }
-    private static int workerCountOf(int c)  { return c & CAPACITY; }
+    private static int runStateOf(int c)     { return c & ~COUNT_MASK; }
+    private static int workerCountOf(int c)  { return c & COUNT_MASK; }
     private static int ctlOf(int rs, int wc) { return rs | wc; }
 
     /*
@@ -449,7 +437,7 @@
      * decrements are performed within getTask.
      */
     private void decrementWorkerCount() {
-        do {} while (! compareAndDecrementWorkerCount(ctl.get()));
+        ctl.addAndGet(-1);
     }
 
     /**
@@ -555,12 +543,17 @@
      * Core pool size is the minimum number of workers to keep alive
      * (and not allow to time out etc) unless allowCoreThreadTimeOut
      * is set, in which case the minimum is zero.
+     *
+     * Since the worker count is actually stored in COUNT_BITS bits,
+     * the effective limit is {@code corePoolSize & COUNT_MASK}.
      */
     private volatile int corePoolSize;
 
     /**
-     * Maximum pool size. Note that the actual maximum is internally
-     * bounded by CAPACITY.
+     * Maximum pool size.
+     *
+     * Since the worker count is actually stored in COUNT_BITS bits,
+     * the effective limit is {@code maximumPoolSize & COUNT_MASK}.
      */
     private volatile int maximumPoolSize;
 
@@ -626,6 +619,9 @@
         /** Per-thread task counter */
         volatile long completedTasks;
 
+        // TODO: switch to AbstractQueuedLongSynchronizer and move
+        // completedTasks into the lock word.
+
         /**
          * Creates with given first task and thread from ThreadFactory.
          * @param firstTask the first task (null if none)
@@ -716,7 +712,7 @@
             int c = ctl.get();
             if (isRunning(c) ||
                 runStateAtLeast(c, TIDYING) ||
-                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+                (runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
                 return;
             if (workerCountOf(c) != 0) { // Eligible to terminate
                 interruptIdleWorkers(ONLY_ONE);
@@ -755,17 +751,12 @@
      * specially.
      */
     private void checkShutdownAccess() {
+        // assert mainLock.isHeldByCurrentThread();
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
             security.checkPermission(shutdownPerm);
-            final ReentrantLock mainLock = this.mainLock;
-            mainLock.lock();
-            try {
-                for (Worker w : workers)
-                    security.checkAccess(w.thread);
-            } finally {
-                mainLock.unlock();
-            }
+            for (Worker w : workers)
+                security.checkAccess(w.thread);
         }
     }
 
@@ -774,14 +765,9 @@
      * (in which case some threads may remain uninterrupted).
      */
     private void interruptWorkers() {
-        final ReentrantLock mainLock = this.mainLock;
-        mainLock.lock();
-        try {
-            for (Worker w : workers)
-                w.interruptIfStarted();
-        } finally {
-            mainLock.unlock();
-        }
+        // assert mainLock.isHeldByCurrentThread();
+        for (Worker w : workers)
+            w.interruptIfStarted();
     }
 
     /**
@@ -857,17 +843,6 @@
     }
 
     /**
-     * State check needed by ScheduledThreadPoolExecutor to
-     * enable running tasks during shutdown.
-     *
-     * @param shutdownOK true if should return true if SHUTDOWN
-     */
-    final boolean isRunningOrShutdown(boolean shutdownOK) {
-        int rs = runStateOf(ctl.get());
-        return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
-    }
-
-    /**
      * Drains the task queue into a new list, normally using
      * drainTo. But if the queue is a DelayQueue or any other kind of
      * queue for which poll or drainTo may fail to remove some
@@ -918,26 +893,22 @@
      */
     private boolean addWorker(Runnable firstTask, boolean core) {
         retry:
-        for (;;) {
-            int c = ctl.get();
-            int rs = runStateOf(c);
-
+        for (int c = ctl.get();;) {
             // Check if queue empty only if necessary.
-            if (rs >= SHUTDOWN &&
-                ! (rs == SHUTDOWN &&
-                   firstTask == null &&
-                   ! workQueue.isEmpty()))
+            if (runStateAtLeast(c, SHUTDOWN)
+                && (runStateAtLeast(c, STOP)
+                    || firstTask != null
+                    || workQueue.isEmpty()))
                 return false;
 
             for (;;) {
-                int wc = workerCountOf(c);
-                if (wc >= CAPACITY ||
-                    wc >= (core ? corePoolSize : maximumPoolSize))
+                if (workerCountOf(c)
+                    >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
                     return false;
                 if (compareAndIncrementWorkerCount(c))
                     break retry;
                 c = ctl.get();  // Re-read ctl
-                if (runStateOf(c) != rs)
+                if (runStateAtLeast(c, SHUTDOWN))
                     continue retry;
                 // else CAS failed due to workerCount change; retry inner loop
             }
@@ -956,10 +927,10 @@
                     // Recheck while holding lock.
                     // Back out on ThreadFactory failure or if
                     // shut down before lock acquired.
-                    int rs = runStateOf(ctl.get());
+                    int c = ctl.get();
 
-                    if (rs < SHUTDOWN ||
-                        (rs == SHUTDOWN && firstTask == null)) {
+                    if (isRunning(c) ||
+                        (runStateLessThan(c, STOP) && firstTask == null)) {
                         if (t.isAlive()) // precheck that t is startable
                             throw new IllegalThreadStateException();
                         workers.add(w);
@@ -1066,10 +1037,10 @@
 
         for (;;) {
             int c = ctl.get();
-            int rs = runStateOf(c);
 
             // Check if queue empty only if necessary.
-            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+            if (runStateAtLeast(c, SHUTDOWN)
+                && (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
                 decrementWorkerCount();
                 return null;
             }
@@ -1162,17 +1133,12 @@
                     wt.interrupt();
                 try {
                     beforeExecute(wt, task);
-                    Throwable thrown = null;
                     try {
                         task.run();
-                    } catch (RuntimeException x) {
-                        thrown = x; throw x;
-                    } catch (Error x) {
-                        thrown = x; throw x;
-                    } catch (Throwable x) {
-                        thrown = x; throw new Error(x);
-                    } finally {
-                        afterExecute(task, thrown);
+                        afterExecute(task, null);
+                    } catch (Throwable ex) {
+                        afterExecute(task, ex);
+                        throw ex;
                     }
                 } finally {
                     task = null;
@@ -1190,9 +1156,11 @@
 
     /**
      * Creates a new {@code ThreadPoolExecutor} with the given initial
-     * parameters and default thread factory and rejected execution handler.
-     * It may be more convenient to use one of the {@link Executors} factory
-     * methods instead of this general purpose constructor.
+     * parameters, the default thread factory and the default rejected
+     * execution handler.
+     *
+     * <p>It may be more convenient to use one of the {@link Executors}
+     * factory methods instead of this general purpose constructor.
      *
      * @param corePoolSize the number of threads to keep in the pool, even
      *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1223,7 +1191,8 @@
 
     /**
      * Creates a new {@code ThreadPoolExecutor} with the given initial
-     * parameters and default rejected execution handler.
+     * parameters and {@linkplain ThreadPoolExecutor.AbortPolicy
+     * default rejected execution handler}.
      *
      * @param corePoolSize the number of threads to keep in the pool, even
      *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1258,7 +1227,8 @@
 
     /**
      * Creates a new {@code ThreadPoolExecutor} with the given initial
-     * parameters and default thread factory.
+     * parameters and
+     * {@linkplain Executors#defaultThreadFactory default thread factory}.
      *
      * @param corePoolSize the number of threads to keep in the pool, even
      *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1346,7 +1316,7 @@
      *
      * If the task cannot be submitted for execution, either because this
      * executor has been shutdown or because its capacity has been reached,
-     * the task is handled by the current {@code RejectedExecutionHandler}.
+     * the task is handled by the current {@link RejectedExecutionHandler}.
      *
      * @param command the task to execute
      * @throws RejectedExecutionException at discretion of
@@ -1451,7 +1421,12 @@
     }
 
     public boolean isShutdown() {
-        return ! isRunning(ctl.get());
+        return runStateAtLeast(ctl.get(), SHUTDOWN);
+    }
+
+    /** Used by ScheduledThreadPoolExecutor. */
+    boolean isStopped() {
+        return runStateAtLeast(ctl.get(), STOP);
     }
 
     /**
@@ -1467,7 +1442,7 @@
      */
     public boolean isTerminating() {
         int c = ctl.get();
-        return ! isRunning(c) && runStateLessThan(c, TERMINATED);
+        return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
     }
 
     public boolean isTerminated() {
@@ -1480,7 +1455,7 @@
         final ReentrantLock mainLock = this.mainLock;
         mainLock.lock();
         try {
-            while (!runStateAtLeast(ctl.get(), TERMINATED)) {
+            while (runStateLessThan(ctl.get(), TERMINATED)) {
                 if (nanos <= 0L)
                     return false;
                 nanos = termination.awaitNanos(nanos);
@@ -1491,13 +1466,21 @@
         }
     }
 
+    // Override without "throws Throwable" for compatibility with subclasses
+    // whose finalize method invokes super.finalize() (as is recommended).
+    // Before JDK 11, finalize() had a non-empty method body.
+
+    // Android-added: The @deprecated javadoc tag
     /**
-     * Invokes {@code shutdown} when this executor is no longer
-     * referenced and it has no threads.
+     * @implNote Previous versions of this class had a finalize method
+     * that shut down this executor, but in this version, finalize
+     * does nothing.
+     *
+     * @deprecated Subclass is not recommended to override finalize(). If it
+     * must, please always invoke super.finalize().
      */
-    protected void finalize() {
-        shutdown();
-    }
+    @Deprecated(since="9")
+    protected void finalize() {}
 
     /**
      * Sets the thread factory used to create new threads.
@@ -1946,7 +1929,7 @@
         }
         int c = ctl.get();
         String runState =
-            runStateLessThan(c, SHUTDOWN) ? "Running" :
+            isRunning(c) ? "Running" :
             runStateAtLeast(c, TERMINATED) ? "Terminated" :
             "Shutting down";
         return super.toString() +
@@ -2065,7 +2048,10 @@
 
     /**
      * A handler for rejected tasks that throws a
-     * {@code RejectedExecutionException}.
+     * {@link RejectedExecutionException}.
+     *
+     * This is the default handler for {@link ThreadPoolExecutor} and
+     * {@link ScheduledThreadPoolExecutor}.
      */
     public static class AbortPolicy implements RejectedExecutionHandler {
         /**
diff --git a/ojluni/src/main/java/java/util/concurrent/TimeUnit.java b/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
index 44d7964..f02aa9f 100644
--- a/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
+++ b/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
 import java.util.Objects;
 
 /**
@@ -74,136 +76,93 @@
     /**
      * Time unit representing one thousandth of a microsecond.
      */
-    NANOSECONDS {
-        public long toNanos(long d)   { return d; }
-        public long toMicros(long d)  { return d/(C1/C0); }
-        public long toMillis(long d)  { return d/(C2/C0); }
-        public long toSeconds(long d) { return d/(C3/C0); }
-        public long toMinutes(long d) { return d/(C4/C0); }
-        public long toHours(long d)   { return d/(C5/C0); }
-        public long toDays(long d)    { return d/(C6/C0); }
-        public long convert(long d, TimeUnit u) { return u.toNanos(d); }
-        int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
-    },
-
+    NANOSECONDS(TimeUnit.NANO_SCALE),
     /**
      * Time unit representing one thousandth of a millisecond.
      */
-    MICROSECONDS {
-        public long toNanos(long d)   { return x(d, C1/C0, MAX/(C1/C0)); }
-        public long toMicros(long d)  { return d; }
-        public long toMillis(long d)  { return d/(C2/C1); }
-        public long toSeconds(long d) { return d/(C3/C1); }
-        public long toMinutes(long d) { return d/(C4/C1); }
-        public long toHours(long d)   { return d/(C5/C1); }
-        public long toDays(long d)    { return d/(C6/C1); }
-        public long convert(long d, TimeUnit u) { return u.toMicros(d); }
-        int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
-    },
-
+    MICROSECONDS(TimeUnit.MICRO_SCALE),
     /**
      * Time unit representing one thousandth of a second.
      */
-    MILLISECONDS {
-        public long toNanos(long d)   { return x(d, C2/C0, MAX/(C2/C0)); }
-        public long toMicros(long d)  { return x(d, C2/C1, MAX/(C2/C1)); }
-        public long toMillis(long d)  { return d; }
-        public long toSeconds(long d) { return d/(C3/C2); }
-        public long toMinutes(long d) { return d/(C4/C2); }
-        public long toHours(long d)   { return d/(C5/C2); }
-        public long toDays(long d)    { return d/(C6/C2); }
-        public long convert(long d, TimeUnit u) { return u.toMillis(d); }
-        int excessNanos(long d, long m) { return 0; }
-    },
-
+    MILLISECONDS(TimeUnit.MILLI_SCALE),
     /**
      * Time unit representing one second.
      */
-    SECONDS {
-        public long toNanos(long d)   { return x(d, C3/C0, MAX/(C3/C0)); }
-        public long toMicros(long d)  { return x(d, C3/C1, MAX/(C3/C1)); }
-        public long toMillis(long d)  { return x(d, C3/C2, MAX/(C3/C2)); }
-        public long toSeconds(long d) { return d; }
-        public long toMinutes(long d) { return d/(C4/C3); }
-        public long toHours(long d)   { return d/(C5/C3); }
-        public long toDays(long d)    { return d/(C6/C3); }
-        public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
-        int excessNanos(long d, long m) { return 0; }
-    },
-
+    SECONDS(TimeUnit.SECOND_SCALE),
     /**
      * Time unit representing sixty seconds.
      * @since 1.6
      */
-    MINUTES {
-        public long toNanos(long d)   { return x(d, C4/C0, MAX/(C4/C0)); }
-        public long toMicros(long d)  { return x(d, C4/C1, MAX/(C4/C1)); }
-        public long toMillis(long d)  { return x(d, C4/C2, MAX/(C4/C2)); }
-        public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); }
-        public long toMinutes(long d) { return d; }
-        public long toHours(long d)   { return d/(C5/C4); }
-        public long toDays(long d)    { return d/(C6/C4); }
-        public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
-        int excessNanos(long d, long m) { return 0; }
-    },
-
+    MINUTES(TimeUnit.MINUTE_SCALE),
     /**
      * Time unit representing sixty minutes.
      * @since 1.6
      */
-    HOURS {
-        public long toNanos(long d)   { return x(d, C5/C0, MAX/(C5/C0)); }
-        public long toMicros(long d)  { return x(d, C5/C1, MAX/(C5/C1)); }
-        public long toMillis(long d)  { return x(d, C5/C2, MAX/(C5/C2)); }
-        public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); }
-        public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); }
-        public long toHours(long d)   { return d; }
-        public long toDays(long d)    { return d/(C6/C5); }
-        public long convert(long d, TimeUnit u) { return u.toHours(d); }
-        int excessNanos(long d, long m) { return 0; }
-    },
-
+    HOURS(TimeUnit.HOUR_SCALE),
     /**
      * Time unit representing twenty four hours.
      * @since 1.6
      */
-    DAYS {
-        public long toNanos(long d)   { return x(d, C6/C0, MAX/(C6/C0)); }
-        public long toMicros(long d)  { return x(d, C6/C1, MAX/(C6/C1)); }
-        public long toMillis(long d)  { return x(d, C6/C2, MAX/(C6/C2)); }
-        public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); }
-        public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); }
-        public long toHours(long d)   { return x(d, C6/C5, MAX/(C6/C5)); }
-        public long toDays(long d)    { return d; }
-        public long convert(long d, TimeUnit u) { return u.toDays(d); }
-        int excessNanos(long d, long m) { return 0; }
-    };
+    DAYS(TimeUnit.DAY_SCALE);
 
-    // Handy constants for conversion methods
-    static final long C0 = 1L;
-    static final long C1 = C0 * 1000L;
-    static final long C2 = C1 * 1000L;
-    static final long C3 = C2 * 1000L;
-    static final long C4 = C3 * 60L;
-    static final long C5 = C4 * 60L;
-    static final long C6 = C5 * 24L;
+    // Scales as constants
+    private static final long NANO_SCALE   = 1L;
+    private static final long MICRO_SCALE  = 1000L * NANO_SCALE;
+    private static final long MILLI_SCALE  = 1000L * MICRO_SCALE;
+    private static final long SECOND_SCALE = 1000L * MILLI_SCALE;
+    private static final long MINUTE_SCALE = 60L * SECOND_SCALE;
+    private static final long HOUR_SCALE   = 60L * MINUTE_SCALE;
+    private static final long DAY_SCALE    = 24L * HOUR_SCALE;
 
-    static final long MAX = Long.MAX_VALUE;
-
-    /**
-     * Scale d by m, checking for overflow.
-     * This has a short name to make above code more readable.
+    /*
+     * Instances cache conversion ratios and saturation cutoffs for
+     * the units up through SECONDS. Other cases compute them, in
+     * method cvt.
      */
-    static long x(long d, long m, long over) {
-        if (d > +over) return Long.MAX_VALUE;
-        if (d < -over) return Long.MIN_VALUE;
-        return d * m;
+
+    private final long scale;
+    private final long maxNanos;
+    private final long maxMicros;
+    private final long maxMillis;
+    private final long maxSecs;
+    private final long microRatio;
+    private final int milliRatio;   // fits in 32 bits
+    private final int secRatio;     // fits in 32 bits
+
+    private TimeUnit(long s) {
+        this.scale = s;
+        this.maxNanos = Long.MAX_VALUE / s;
+        long ur = (s >= MICRO_SCALE) ? (s / MICRO_SCALE) : (MICRO_SCALE / s);
+        this.microRatio = ur;
+        this.maxMicros = Long.MAX_VALUE / ur;
+        long mr = (s >= MILLI_SCALE) ? (s / MILLI_SCALE) : (MILLI_SCALE / s);
+        this.milliRatio = (int)mr;
+        this.maxMillis = Long.MAX_VALUE / mr;
+        long sr = (s >= SECOND_SCALE) ? (s / SECOND_SCALE) : (SECOND_SCALE / s);
+        this.secRatio = (int)sr;
+        this.maxSecs = Long.MAX_VALUE / sr;
     }
 
-    // To maintain full signature compatibility with 1.5, and to improve the
-    // clarity of the generated javadoc (see 6287639: Abstract methods in
-    // enum classes should not be listed as abstract), method convert
-    // etc. are not declared abstract but otherwise act as abstract methods.
+    /**
+     * General conversion utility.
+     *
+     * @param d duration
+     * @param dst result unit scale
+     * @param src source unit scale
+     */
+    private static long cvt(long d, long dst, long src) {
+        long r, m;
+        if (src == dst)
+            return d;
+        else if (src < dst)
+            return d / (dst / src);
+        else if (d > (m = Long.MAX_VALUE / (r = src / dst)))
+            return Long.MAX_VALUE;
+        else if (d < -m)
+            return Long.MIN_VALUE;
+        else
+            return d * r;
+    }
 
     /**
      * Converts the given time duration in the given unit to this unit.
@@ -220,11 +179,65 @@
      * @param sourceDuration the time duration in the given {@code sourceUnit}
      * @param sourceUnit the unit of the {@code sourceDuration} argument
      * @return the converted duration in this unit,
-     * or {@code Long.MIN_VALUE} if conversion would negatively
-     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long convert(long sourceDuration, TimeUnit sourceUnit) {
-        throw new AbstractMethodError();
+        switch (this) {
+        case NANOSECONDS:  return sourceUnit.toNanos(sourceDuration);
+        case MICROSECONDS: return sourceUnit.toMicros(sourceDuration);
+        case MILLISECONDS: return sourceUnit.toMillis(sourceDuration);
+        case SECONDS:      return sourceUnit.toSeconds(sourceDuration);
+        default: return cvt(sourceDuration, scale, sourceUnit.scale);
+        }
+    }
+
+    /**
+     * Converts the given time duration to this unit.
+     *
+     * <p>For any TimeUnit {@code unit},
+     * {@code unit.convert(Duration.ofNanos(n))}
+     * is equivalent to
+     * {@code unit.convert(n, NANOSECONDS)}, and
+     * {@code unit.convert(Duration.of(n, unit.toChronoUnit()))}
+     * is equivalent to {@code n} (in the absence of overflow).
+     *
+     * @apiNote
+     * This method differs from {@link Duration#toNanos()} in that it
+     * does not throw {@link ArithmeticException} on numeric overflow.
+     *
+     * @param duration the time duration
+     * @return the converted duration in this unit,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * @throws NullPointerException if {@code duration} is null
+     * @see Duration#of(long,TemporalUnit)
+     * @since 11
+     */
+    public long convert(Duration duration) {
+        long secs = duration.getSeconds();
+        int nano = duration.getNano();
+        if (secs < 0 && nano > 0) {
+            // use representation compatible with integer division
+            secs++;
+            nano -= (int) SECOND_SCALE;
+        }
+        final long s, nanoVal;
+        // Optimize for the common case - NANOSECONDS without overflow
+        if (this == NANOSECONDS)
+            nanoVal = nano;
+        else if ((s = scale) < SECOND_SCALE)
+            nanoVal = nano / s;
+        else if (this == SECONDS)
+            return secs;
+        else
+            return secs / secRatio;
+        long val = secs * secRatio + nanoVal;
+        return ((secs < maxSecs && secs > -maxSecs) ||
+                (secs == maxSecs && val > 0) ||
+                (secs == -maxSecs && val < 0))
+            ? val
+            : (secs > 0) ? Long.MAX_VALUE : Long.MIN_VALUE;
     }
 
     /**
@@ -232,11 +245,19 @@
      * {@link #convert(long, TimeUnit) NANOSECONDS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively
-     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long toNanos(long duration) {
-        throw new AbstractMethodError();
+        long s, m;
+        if ((s = scale) == NANO_SCALE)
+            return duration;
+        else if (duration > (m = maxNanos))
+            return Long.MAX_VALUE;
+        else if (duration < -m)
+            return Long.MIN_VALUE;
+        else
+            return duration * s;
     }
 
     /**
@@ -244,11 +265,19 @@
      * {@link #convert(long, TimeUnit) MICROSECONDS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively
-     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long toMicros(long duration) {
-        throw new AbstractMethodError();
+        long s, m;
+        if ((s = scale) <= MICRO_SCALE)
+            return (s == MICRO_SCALE) ? duration : duration / microRatio;
+        else if (duration > (m = maxMicros))
+            return Long.MAX_VALUE;
+        else if (duration < -m)
+            return Long.MIN_VALUE;
+        else
+            return duration * microRatio;
     }
 
     /**
@@ -256,11 +285,19 @@
      * {@link #convert(long, TimeUnit) MILLISECONDS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively
-     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long toMillis(long duration) {
-        throw new AbstractMethodError();
+        long s, m;
+        if ((s = scale) <= MILLI_SCALE)
+            return (s == MILLI_SCALE) ? duration : duration / milliRatio;
+        else if (duration > (m = maxMillis))
+            return Long.MAX_VALUE;
+        else if (duration < -m)
+            return Long.MIN_VALUE;
+        else
+            return duration * milliRatio;
     }
 
     /**
@@ -268,11 +305,19 @@
      * {@link #convert(long, TimeUnit) SECONDS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively
-     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
      */
     public long toSeconds(long duration) {
-        throw new AbstractMethodError();
+        long s, m;
+        if ((s = scale) <= SECOND_SCALE)
+            return (s == SECOND_SCALE) ? duration : duration / secRatio;
+        else if (duration > (m = maxSecs))
+            return Long.MAX_VALUE;
+        else if (duration < -m)
+            return Long.MIN_VALUE;
+        else
+            return duration * secRatio;
     }
 
     /**
@@ -280,12 +325,12 @@
      * {@link #convert(long, TimeUnit) MINUTES.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively
-     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
      * @since 1.6
      */
     public long toMinutes(long duration) {
-        throw new AbstractMethodError();
+        return cvt(duration, MINUTE_SCALE, scale);
     }
 
     /**
@@ -293,12 +338,12 @@
      * {@link #convert(long, TimeUnit) HOURS.convert(duration, this)}.
      * @param duration the duration
      * @return the converted duration,
-     * or {@code Long.MIN_VALUE} if conversion would negatively
-     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
      * @since 1.6
      */
     public long toHours(long duration) {
-        throw new AbstractMethodError();
+        return cvt(duration, HOUR_SCALE, scale);
     }
 
     /**
@@ -309,7 +354,7 @@
      * @since 1.6
      */
     public long toDays(long duration) {
-        throw new AbstractMethodError();
+        return cvt(duration, DAY_SCALE, scale);
     }
 
     /**
@@ -319,7 +364,15 @@
      * @param m the number of milliseconds
      * @return the number of nanoseconds
      */
-    abstract int excessNanos(long d, long m);
+    private int excessNanos(long d, long m) {
+        long s;
+        if ((s = scale) == NANO_SCALE)
+            return (int)(d - (m * MILLI_SCALE));
+        else if (s == MICRO_SCALE)
+            return (int)((d * 1000L) - (m * MILLI_SCALE));
+        else
+            return 0;
+    }
 
     /**
      * Performs a timed {@link Object#wait(long, int) Object.wait}
@@ -327,16 +380,18 @@
      * This is a convenience method that converts timeout arguments
      * into the form required by the {@code Object.wait} method.
      *
-     * <p>For example, you could implement a blocking {@code poll}
-     * method (see {@link BlockingQueue#poll BlockingQueue.poll})
+     * <p>For example, you could implement a blocking {@code poll} method
+     * (see {@link BlockingQueue#poll(long, TimeUnit) BlockingQueue.poll})
      * using:
      *
      * <pre> {@code
-     * public synchronized Object poll(long timeout, TimeUnit unit)
+     * public E poll(long timeout, TimeUnit unit)
      *     throws InterruptedException {
-     *   while (empty) {
-     *     unit.timedWait(this, timeout);
-     *     ...
+     *   synchronized (lock) {
+     *     while (isEmpty()) {
+     *       unit.timedWait(lock, timeout);
+     *       ...
+     *     }
      *   }
      * }}</pre>
      *
@@ -392,14 +447,12 @@
         }
     }
 
-    // BEGIN Android-removed: OpenJDK 9 ChronoUnit related code.
-    /*
     /**
      * Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}.
      *
      * @return the converted equivalent ChronoUnit
      * @since 9
-     *
+     */
     public ChronoUnit toChronoUnit() {
         switch (this) {
         case NANOSECONDS:  return ChronoUnit.NANOS;
@@ -422,7 +475,7 @@
      *         equivalent TimeUnit
      * @throws NullPointerException if {@code chronoUnit} is null
      * @since 9
-     *
+     */
     public static TimeUnit of(ChronoUnit chronoUnit) {
         switch (Objects.requireNonNull(chronoUnit, "chronoUnit")) {
         case NANOS:   return TimeUnit.NANOSECONDS;
@@ -437,7 +490,5 @@
                 "No TimeUnit equivalent for " + chronoUnit);
         }
     }
-    */
-    // END Android-removed: OpenJDK 9 ChronoUnit related code.
 
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/TransferQueue.java b/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
index 53da597..72a4108 100644
--- a/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
@@ -35,10 +35,6 @@
 
 package java.util.concurrent;
 
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
 /**
  * A {@link BlockingQueue} in which producers may wait for consumers
  * to receive elements.  A {@code TransferQueue} may be useful for
@@ -61,6 +57,10 @@
  * with zero capacity, such as {@link SynchronousQueue}, {@code put}
  * and {@code transfer} are effectively synonymous.
  *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
  * @since 1.7
  * @author Doug Lea
  * @param <E> the type of elements held in this queue
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index 447a642..34a200b 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -40,10 +40,13 @@
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+import java.lang.invoke.VarHandle;
 
 /**
  * A reflection-based utility that enables atomic updates to
@@ -59,6 +62,10 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
@@ -107,8 +114,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean compareAndSet(T obj, long expect, long update);
 
@@ -127,8 +132,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean weakCompareAndSet(T obj, long expect, long update);
 
@@ -153,8 +156,8 @@
     public abstract void lazySet(T obj, long newValue);
 
     /**
-     * Gets the current value held in the field of the given object managed
-     * by this updater.
+     * Returns the current value held in the field of the given object
+     * managed by this updater.
      *
      * @param obj An object whose field to get
      * @return the current value
@@ -276,10 +279,12 @@
     }
 
     /**
-     * Atomically updates the field of the given object managed by this updater
-     * with the results of applying the given function, returning the previous
-     * value. The function should be side-effect-free, since it may be
-     * re-applied when attempted updates fail due to contention among threads.
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
      *
      * @param obj An object whose field to get and set
      * @param updateFunction a side-effect-free function
@@ -296,10 +301,12 @@
     }
 
     /**
-     * Atomically updates the field of the given object managed by this updater
-     * with the results of applying the given function, returning the updated
-     * value. The function should be side-effect-free, since it may be
-     * re-applied when attempted updates fail due to contention among threads.
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
      *
      * @param obj An object whose field to get and set
      * @param updateFunction a side-effect-free function
@@ -316,13 +323,14 @@
     }
 
     /**
-     * Atomically updates the field of the given object managed by this
-     * updater with the results of applying the given function to the
-     * current and given values, returning the previous value. The
-     * function should be side-effect-free, since it may be re-applied
-     * when attempted updates fail due to contention among threads.  The
-     * function is applied with the current value as its first argument,
-     * and the given update as the second argument.
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the previous value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
      *
      * @param obj An object whose field to get and set
      * @param x the update value
@@ -341,13 +349,14 @@
     }
 
     /**
-     * Atomically updates the field of the given object managed by this
-     * updater with the results of applying the given function to the
-     * current and given values, returning the updated value. The
-     * function should be side-effect-free, since it may be re-applied
-     * when attempted updates fail due to contention among threads.  The
-     * function is applied with the current value as its first argument,
-     * and the given update as the second argument.
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the updated value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
      *
      * @param obj An object whose field to get and set
      * @param x the update value
@@ -366,7 +375,7 @@
     }
 
     private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final Unsafe U = Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
@@ -418,7 +427,17 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
             this.tclass = tclass;
             this.offset = U.objectFieldOffset(field);
         }
@@ -452,12 +471,12 @@
 
         public final boolean compareAndSet(T obj, long expect, long update) {
             accessCheck(obj);
-            return U.compareAndSwapLong(obj, offset, expect, update);
+            return U.compareAndSetLong(obj, offset, expect, update);
         }
 
         public final boolean weakCompareAndSet(T obj, long expect, long update) {
             accessCheck(obj);
-            return U.compareAndSwapLong(obj, offset, expect, update);
+            return U.compareAndSetLong(obj, offset, expect, update);
         }
 
         public final void set(T obj, long newValue) {
@@ -467,7 +486,7 @@
 
         public final void lazySet(T obj, long newValue) {
             accessCheck(obj);
-            U.putOrderedLong(obj, offset, newValue);
+            U.putLongRelease(obj, offset, newValue);
         }
 
         public final long get(T obj) {
@@ -507,7 +526,7 @@
     }
 
     private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final Unsafe U = Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
@@ -519,8 +538,8 @@
 
         LockedUpdater(final Class<T> tclass, final String fieldName,
                       final Class<?> caller) {
-            Field field = null;
-            int modifiers = 0;
+            final Field field;
+            final int modifiers;
             try {
                 // Android-changed: Skip privilege escalation which is a noop on Android.
                 /*
@@ -559,7 +578,17 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
             this.tclass = tclass;
             this.offset = U.objectFieldOffset(field);
         }
@@ -643,4 +672,13 @@
         return false;
     }
     */
+
+    /**
+     * Returns true if the two classes have the same class loader and
+     * package qualifier
+     */
+    static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+        return class1.getClassLoader() == class2.getClassLoader()
+            && Objects.equals(class1.getPackageName(), class2.getPackageName());
+    }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
index b49118b..51ea84c 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -35,6 +35,9 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
 /**
  * An {@code AtomicMarkableReference} maintains an object reference
  * along with a mark bit, that can be updated atomically.
@@ -188,20 +191,19 @@
              casPair(current, Pair.of(expectedReference, newMark)));
     }
 
-    // Unsafe mechanics
-
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long PAIR;
+    // VarHandle mechanics
+    private static final VarHandle PAIR;
     static {
         try {
-            PAIR = U.objectFieldOffset
-                (AtomicMarkableReference.class.getDeclaredField("pair"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
+                                   Pair.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
     private boolean casPair(Pair<V> cmp, Pair<V> val) {
-        return U.compareAndSwapObject(this, PAIR, cmp, val);
+        return PAIR.compareAndSet(this, cmp, val);
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index 17423ad..513a243 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -40,10 +40,13 @@
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
 import java.util.function.BinaryOperator;
 import java.util.function.UnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+import java.lang.invoke.VarHandle;
 
 /**
  * A reflection-based utility that enables atomic updates to
@@ -76,6 +79,10 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
@@ -168,8 +175,8 @@
     public abstract void lazySet(T obj, V newValue);
 
     /**
-     * Gets the current value held in the field of the given object managed
-     * by this updater.
+     * Returns the current value held in the field of the given object
+     * managed by this updater.
      *
      * @param obj An object whose field to get
      * @return the current value
@@ -193,10 +200,12 @@
     }
 
     /**
-     * Atomically updates the field of the given object managed by this updater
-     * with the results of applying the given function, returning the previous
-     * value. The function should be side-effect-free, since it may be
-     * re-applied when attempted updates fail due to contention among threads.
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
      *
      * @param obj An object whose field to get and set
      * @param updateFunction a side-effect-free function
@@ -213,10 +222,12 @@
     }
 
     /**
-     * Atomically updates the field of the given object managed by this updater
-     * with the results of applying the given function, returning the updated
-     * value. The function should be side-effect-free, since it may be
-     * re-applied when attempted updates fail due to contention among threads.
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
      *
      * @param obj An object whose field to get and set
      * @param updateFunction a side-effect-free function
@@ -233,13 +244,14 @@
     }
 
     /**
-     * Atomically updates the field of the given object managed by this
-     * updater with the results of applying the given function to the
-     * current and given values, returning the previous value. The
-     * function should be side-effect-free, since it may be re-applied
-     * when attempted updates fail due to contention among threads.  The
-     * function is applied with the current value as its first argument,
-     * and the given update as the second argument.
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the previous value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
      *
      * @param obj An object whose field to get and set
      * @param x the update value
@@ -258,13 +270,14 @@
     }
 
     /**
-     * Atomically updates the field of the given object managed by this
-     * updater with the results of applying the given function to the
-     * current and given values, returning the updated value. The
-     * function should be side-effect-free, since it may be re-applied
-     * when attempted updates fail due to contention among threads.  The
-     * function is applied with the current value as its first argument,
-     * and the given update as the second argument.
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the updated value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
      *
      * @param obj An object whose field to get and set
      * @param x the update value
@@ -284,7 +297,7 @@
 
     private static final class AtomicReferenceFieldUpdaterImpl<T,V>
         extends AtomicReferenceFieldUpdater<T,V> {
-        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final Unsafe U = Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
@@ -356,7 +369,17 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
             this.tclass = tclass;
             this.vclass = vclass;
             this.offset = U.objectFieldOffset(field);
@@ -382,6 +405,15 @@
         */
 
         /**
+         * Returns true if the two classes have the same class loader and
+         * package qualifier
+         */
+        private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+            return class1.getClassLoader() == class2.getClassLoader()
+                   && Objects.equals(class1.getPackageName(), class2.getPackageName());
+        }
+
+        /**
          * Checks that target argument is instance of cclass.  On
          * failure, throws cause.
          */
@@ -420,14 +452,14 @@
         public final boolean compareAndSet(T obj, V expect, V update) {
             accessCheck(obj);
             valueCheck(update);
-            return U.compareAndSwapObject(obj, offset, expect, update);
+            return U.compareAndSetObject(obj, offset, expect, update);
         }
 
         public final boolean weakCompareAndSet(T obj, V expect, V update) {
             // same implementation as strong form for now
             accessCheck(obj);
             valueCheck(update);
-            return U.compareAndSwapObject(obj, offset, expect, update);
+            return U.compareAndSetObject(obj, offset, expect, update);
         }
 
         public final void set(T obj, V newValue) {
@@ -439,7 +471,7 @@
         public final void lazySet(T obj, V newValue) {
             accessCheck(obj);
             valueCheck(newValue);
-            U.putOrderedObject(obj, offset, newValue);
+            U.putObjectRelease(obj, offset, newValue);
         }
 
         @SuppressWarnings("unchecked")
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
index 40ceeb2..47b7c7b 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -35,6 +35,9 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
 /**
  * An {@code AtomicStampedReference} maintains an object reference
  * along with an integer "stamp", that can be updated atomically.
@@ -188,20 +191,19 @@
              casPair(current, Pair.of(expectedReference, newStamp)));
     }
 
-    // Unsafe mechanics
-
-    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
-    private static final long PAIR;
+    // VarHandle mechanics
+    private static final VarHandle PAIR;
     static {
         try {
-            PAIR = U.objectFieldOffset
-                (AtomicStampedReference.class.getDeclaredField("pair"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
+                                   Pair.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
     private boolean casPair(Pair<V> cmp, Pair<V> val) {
-        return U.compareAndSwapObject(this, PAIR, cmp, val);
+        return PAIR.compareAndSet(this, cmp, val);
     }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/Striped64.java b/ojluni/src/main/java/java/util/concurrent/atomic/Striped64.java
index 2a8f327..2d83d61 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/Striped64.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/Striped64.java
@@ -119,8 +119,7 @@
      * JVM intrinsics note: It would be possible to use a release-only
      * form of CAS here, if it were provided.
      */
-    // Android-removed: @Contended, this hint is not used by the Android runtime.
-    // @jdk.internal.vm.annotation.Contended
+    @jdk.internal.vm.annotation.Contended
     static final class Cell {
         volatile long value;
         Cell(long x) { value = x; }
diff --git a/ojluni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/ojluni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index 50e3c52..4ecfff0 100644
--- a/ojluni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/ojluni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -903,8 +903,6 @@
      * @param arg the acquire argument
      * @return {@code true} if interrupted while waiting
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
     final boolean acquireQueued(final Node node, int arg) {
         boolean interrupted = false;
         try {
@@ -1237,8 +1235,6 @@
      *        {@link #tryAcquire} but is otherwise uninterpreted and
      *        can represent anything you like.
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
     public final void acquire(int arg) {
         if (!tryAcquire(arg) &&
             acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
@@ -1302,8 +1298,6 @@
      *        can represent anything you like.
      * @return the value returned from {@link #tryRelease}
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
     public final boolean release(int arg) {
         if (tryRelease(arg)) {
             Node h = head;
@@ -1384,8 +1378,6 @@
      *        and can represent anything you like.
      * @return the value returned from {@link #tryReleaseShared}
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
     public final boolean releaseShared(int arg) {
         if (tryReleaseShared(arg)) {
             doReleaseShared();
diff --git a/ojluni/src/main/java/java/util/concurrent/locks/ReentrantLock.java b/ojluni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
index 0c5b3e6..1cb7d89 100644
--- a/ojluni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
+++ b/ojluni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
@@ -37,6 +37,7 @@
 
 import java.util.Collection;
 import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
  * A reentrant mutual exclusion {@link Lock} with the same basic
@@ -121,8 +122,7 @@
          * Performs non-fair tryLock.  tryAcquire is implemented in
          * subclasses, but both need nonfair try for trylock method.
          */
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         final boolean nonfairTryAcquire(int acquires) {
             final Thread current = Thread.currentThread();
             int c = getState();
@@ -142,8 +142,7 @@
             return false;
         }
 
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         protected final boolean tryRelease(int releases) {
             int c = getState() - releases;
             if (Thread.currentThread() != getExclusiveOwnerThread())
@@ -210,8 +209,7 @@
          * Fair version of tryAcquire.  Don't grant access unless
          * recursive call or no waiters or is first.
          */
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         protected final boolean tryAcquire(int acquires) {
             final Thread current = Thread.currentThread();
             int c = getState();
diff --git a/ojluni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/ojluni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
index d01e67a..c92e213 100644
--- a/ojluni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
+++ b/ojluni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -37,6 +37,7 @@
 
 import java.util.Collection;
 import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
  * An implementation of {@link ReadWriteLock} supporting similar
@@ -365,8 +366,7 @@
          * both read and write holds that are all released during a
          * condition wait and re-established in tryAcquire.
          */
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         protected final boolean tryRelease(int releases) {
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
@@ -378,8 +378,7 @@
             return free;
         }
 
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         protected final boolean tryAcquire(int acquires) {
             /*
              * Walkthrough:
@@ -412,8 +411,7 @@
             return true;
         }
 
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         protected final boolean tryReleaseShared(int unused) {
             Thread current = Thread.currentThread();
             if (firstReader == current) {
@@ -451,8 +449,7 @@
                 "attempt to unlock read lock, not locked by current thread");
         }
 
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         protected final int tryAcquireShared(int unused) {
             /*
              * Walkthrough:
@@ -563,8 +560,7 @@
          * This is identical in effect to tryAcquire except for lack
          * of calls to writerShouldBlock.
          */
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         final boolean tryWriteLock() {
             Thread current = Thread.currentThread();
             int c = getState();
@@ -586,8 +582,7 @@
          * This is identical in effect to tryAcquireShared except for
          * lack of calls to readerShouldBlock.
          */
-        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-        // @ReservedStackAccess
+        @ReservedStackAccess
         final boolean tryReadLock() {
             Thread current = Thread.currentThread();
             for (;;) {
diff --git a/ojluni/src/main/java/java/util/concurrent/locks/StampedLock.java b/ojluni/src/main/java/java/util/concurrent/locks/StampedLock.java
index 8a2cd35..dbcf9c3 100644
--- a/ojluni/src/main/java/java/util/concurrent/locks/StampedLock.java
+++ b/ojluni/src/main/java/java/util/concurrent/locks/StampedLock.java
@@ -38,6 +38,7 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
  * A capability-based lock with three modes for controlling read/write
@@ -454,8 +455,7 @@
      *
      * @return a write stamp that can be used to unlock or convert mode
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public long writeLock() {
         long next;
         return ((next = tryWriteLock()) != 0L) ? next : acquireWrite(false, 0L);
@@ -467,8 +467,7 @@
      * @return a write stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public long tryWriteLock() {
         long s;
         return (((s = state) & ABITS) == 0L) ? tryWriteLock(s) : 0L;
@@ -514,8 +513,7 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public long writeLockInterruptibly() throws InterruptedException {
         long next;
         if (!Thread.interrupted() &&
@@ -530,8 +528,7 @@
      *
      * @return a read stamp that can be used to unlock or convert mode
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public long readLock() {
         long s, next;
         // bypass acquireRead on common uncontended case
@@ -548,8 +545,7 @@
      * @return a read stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public long tryReadLock() {
         long s, m, next;
         while ((m = (s = state) & ABITS) != WBIT) {
@@ -576,8 +572,7 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public long tryReadLock(long time, TimeUnit unit)
         throws InterruptedException {
         long s, m, next, deadline;
@@ -611,8 +606,7 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public long readLockInterruptibly() throws InterruptedException {
         long s, next;
         if (!Thread.interrupted()
@@ -680,8 +674,7 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public void unlockWrite(long stamp) {
         if (state != stamp || (stamp & WBIT) == 0L)
             throw new IllegalMonitorStateException();
@@ -696,8 +689,7 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public void unlockRead(long stamp) {
         long s, m; WNode h;
         while (((s = state) & SBITS) == (stamp & SBITS)
@@ -724,8 +716,7 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public void unlock(long stamp) {
         if ((stamp & WBIT) != 0L)
             unlockWrite(stamp);
@@ -858,8 +849,7 @@
      *
      * @return {@code true} if the lock was held, else false
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public boolean tryUnlockWrite() {
         long s;
         if (((s = state) & WBIT) != 0L) {
@@ -876,8 +866,7 @@
      *
      * @return {@code true} if the read lock was held, else false
      */
-    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
-    // @ReservedStackAccess
+    @ReservedStackAccess
     public boolean tryUnlockRead() {
         long s, m; WNode h;
         while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
@@ -1176,8 +1165,9 @@
         }
         else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
             Thread.yield();
-        else
-            Thread.onSpinWait();
+        // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+        // else
+        //     Thread.onSpinWait();
         return 0L;
     }
 
@@ -1204,8 +1194,9 @@
         }
         else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
             Thread.yield();
-        else
-            Thread.onSpinWait();
+        // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+        // else
+        //     Thread.onSpinWait();
         return 0L;
     }
 
@@ -1251,7 +1242,8 @@
                 spins = (m == WBIT && wtail == whead) ? SPINS : 0;
             else if (spins > 0) {
                 --spins;
-                Thread.onSpinWait();
+                // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+                // Thread.onSpinWait();
             }
             else if ((p = wtail) == null) { // initialize queue
                 WNode hd = new WNode(WMODE, null);
@@ -1287,8 +1279,9 @@
                             return ns;
                         }
                     }
-                    else
-                        Thread.onSpinWait();
+                    // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+                    // else
+                    //     Thread.onSpinWait();
                 }
             }
             else if (h != null) { // help release stale waiters
@@ -1364,7 +1357,8 @@
                     else if (m >= WBIT) {
                         if (spins > 0) {
                             --spins;
-                            Thread.onSpinWait();
+                            // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+                            // Thread.onSpinWait();
                         }
                         else {
                             if (spins == 0) {
@@ -1473,8 +1467,9 @@
                     }
                     else if (m >= WBIT && --k <= 0)
                         break;
-                    else
-                        Thread.onSpinWait();
+                    // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+                    // else
+                    //     Thread.onSpinWait();
                 }
             }
             else if (h != null) {
diff --git a/ojluni/src/main/java/java/util/concurrent/package-info.java b/ojluni/src/main/java/java/util/concurrent/package-info.java
index 387068d..0e992a2 100644
--- a/ojluni/src/main/java/java/util/concurrent/package-info.java
+++ b/ojluni/src/main/java/java/util/concurrent/package-info.java
@@ -200,7 +200,7 @@
  * concurrent collection is thread-safe, but not governed by a
  * single exclusion lock.  In the particular case of
  * ConcurrentHashMap, it safely permits any number of
- * concurrent reads as well as a tunable number of concurrent
+ * concurrent reads as well as a large number of concurrent
  * writes.  "Synchronized" classes can be useful when you need
  * to prevent all access to a collection via a single lock, at
  * the expense of poorer scalability.  In other cases in which
@@ -262,7 +262,6 @@
  *
  * </ul>
  *
- *
  * The methods of all classes in {@code java.util.concurrent} and its
  * subpackages extend these guarantees to higher-level
  * synchronization.  In particular:
diff --git a/ojluni/src/main/java/java/util/zip/GZIPInputStream.java b/ojluni/src/main/java/java/util/zip/GZIPInputStream.java
index e259505..b2482f4 100644
--- a/ojluni/src/main/java/java/util/zip/GZIPInputStream.java
+++ b/ojluni/src/main/java/java/util/zip/GZIPInputStream.java
@@ -66,6 +66,14 @@
 
     /**
      * Creates a new input stream with the specified buffer size.
+     *
+     * Android-note: Android limits the number of UnbufferedIO operations that can be performed, so
+     * consider using buffered inputs with this class. More information can be found in the
+     * <a href="https://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder#detectUnbufferedIo()">
+     * UnbufferedIO</a> and
+     * <a href="https://developer.android.com/reference/android/os/StrictMode"> StrictMode</a>
+     * documentation.
+     *
      * @param in the input stream
      * @param size the input buffer size
      *
diff --git a/ojluni/src/main/java/java/util/zip/GZIPOutputStream.java b/ojluni/src/main/java/java/util/zip/GZIPOutputStream.java
index 9ff56f1..cad62dc 100644
--- a/ojluni/src/main/java/java/util/zip/GZIPOutputStream.java
+++ b/ojluni/src/main/java/java/util/zip/GZIPOutputStream.java
@@ -59,6 +59,13 @@
      * <p>The new output stream instance is created as if by invoking
      * the 3-argument constructor GZIPOutputStream(out, size, false).
      *
+     * Android-note: Android limits the number of UnbufferedIO operations that can be performed, so
+     * consider using buffered inputs with this class. More information can be found in the
+     * <a href="https://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder#detectUnbufferedIo()">
+     * UnbufferedIO</a> and
+     * <a href="https://developer.android.com/reference/android/os/StrictMode"> StrictMode</a>
+     * documentation.
+     *
      * @param out the output stream
      * @param size the output buffer size
      * @exception IOException If an I/O error has occurred.
diff --git a/ojluni/src/main/java/java/util/zip/ZipInputStream.java b/ojluni/src/main/java/java/util/zip/ZipInputStream.java
index 6ca359d..068c277 100644
--- a/ojluni/src/main/java/java/util/zip/ZipInputStream.java
+++ b/ojluni/src/main/java/java/util/zip/ZipInputStream.java
@@ -324,7 +324,7 @@
         e.method = get16(tmpbuf, LOCHOW);
         e.xdostime = get32(tmpbuf, LOCTIM);
         if ((flag & 8) == 8) {
-            // Android-Changed: Remove the requirement that only DEFLATED entries
+            // Android-changed: Remove the requirement that only DEFLATED entries
             // can have data descriptors. This is not required by the ZIP spec and
             // is inconsistent with the behaviour of ZipFile and versions of Android
             // prior to Android N.
diff --git a/ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java b/ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java
new file mode 100644
index 0000000..cfba310
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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;
+
+import java.lang.annotation.*;
+
+// Android-note: HotSpot-specific implementation notes not relevant for Android.
+/**
+ * The {@code @HotSpotIntrinsicCandidate} annotation is specific to the
+ * HotSpot Virtual Machine. It indicates that an annotated method
+ * may be (but is not guaranteed to be) intrinsified by the HotSpot VM. A method
+ * is intrinsified if the HotSpot VM replaces the annotated method with hand-written
+ * assembly and/or hand-written compiler IR -- a compiler intrinsic -- to improve
+ * performance. The {@code @HotSpotIntrinsicCandidate} annotation is internal to the
+ * Java libraries and is therefore not supposed to have any relevance for application
+ * code.
+ *
+ * Maintainers of the Java libraries must consider the following when
+ * modifying methods annotated with {@code @HotSpotIntrinsicCandidate}.
+ *
+ * <ul>
+ * <li>When modifying a method annotated with {@code @HotSpotIntrinsicCandidate},
+ * the corresponding intrinsic code in the HotSpot VM implementation must be
+ * updated to match the semantics of the annotated method.</li>
+ * <li>For some annotated methods, the corresponding intrinsic may omit some low-level
+ * checks that would be performed as a matter of course if the intrinsic is implemented
+ * using Java bytecodes. This is because individual Java bytecodes implicitly check
+ * for exceptions like {@code NullPointerException} and {@code ArrayStoreException}.
+ * If such a method is replaced by an intrinsic coded in assembly language, any
+ * checks performed as a matter of normal bytecode operation must be performed
+ * before entry into the assembly code. These checks must be performed, as
+ * appropriate, on all arguments to the intrinsic, and on other values (if any) obtained
+ * by the intrinsic through those arguments. The checks may be deduced by inspecting
+ * the non-intrinsic Java code for the method, and determining exactly which exceptions
+ * may be thrown by the code, including undeclared implicit {@code RuntimeException}s.
+ * Therefore, depending on the data accesses performed by the intrinsic,
+ * the checks may include:
+ *
+ *  <ul>
+ *  <li>null checks on references</li>
+ *  <li>range checks on primitive values used as array indexes</li>
+ *  <li>other validity checks on primitive values (e.g., for divide-by-zero conditions)</li>
+ *  <li>store checks on reference values stored into arrays</li>
+ *  <li>array length checks on arrays indexed from within the intrinsic</li>
+ *  <li>reference casts (when formal parameters are {@code Object} or some other weak type)</li>
+ *  </ul>
+ *
+ * </li>
+ *
+ * <li>Note that the receiver value ({@code this}) is passed as a extra argument
+ * to all non-static methods. If a non-static method is an intrinsic, the receiver
+ * value does not need a null check, but (as stated above) any values loaded by the
+ * intrinsic from object fields must also be checked. As a matter of clarity, it is
+ * better to make intrinisics be static methods, to make the dependency on {@code this}
+ * clear. Also, it is better to explicitly load all required values from object
+ * fields before entering the intrinsic code, and pass those values as explicit arguments.
+ * First, this may be necessary for null checks (or other checks). Second, if the
+ * intrinsic reloads the values from fields and operates on those without checks,
+ * race conditions may be able to introduce unchecked invalid values into the intrinsic.
+ * If the intrinsic needs to store a value back to an object field, that value should be
+ * returned explicitly from the intrinsic; if there are multiple return values, coders
+ * should consider buffering them in an array. Removing field access from intrinsics
+ * not only clarifies the interface with between the JVM and JDK; it also helps decouple
+ * the HotSpot and JDK implementations, since if JDK code before and after the intrinsic
+ * manages all field accesses, then intrinsics can be coded to be agnostic of object
+ * layouts.</li>
+ *
+ * Maintainers of the HotSpot VM must consider the following when modifying
+ * intrinsics.
+ *
+ * <ul>
+ * <li>When adding a new intrinsic, make sure that the corresponding method
+ * in the Java libraries is annotated with {@code @HotSpotIntrinsicCandidate}
+ * and that all possible call sequences that result in calling the intrinsic contain
+ * the checks omitted by the intrinsic (if any).</li>
+ * <li>When modifying an existing intrinsic, the Java libraries must be updated
+ * to match the semantics of the intrinsic and to execute all checks omitted
+ * by the intrinsic (if any).</li>
+ * </ul>
+ *
+ * Persons not directly involved with maintaining the Java libraries or the
+ * HotSpot VM can safely ignore the fact that a method is annotated with
+ * {@code @HotSpotIntrinsicCandidate}.
+ *
+ * The HotSpot VM defines (internally) a list of intrinsics. Not all intrinsic
+ * are available on all platforms supported by the HotSpot VM. Furthermore,
+ * the availability of an intrinsic on a given platform depends on the
+ * configuration of the HotSpot VM (e.g., the set of VM flags enabled).
+ * Therefore, annotating a method with {@code @HotSpotIntrinsicCandidate} does
+ * not guarantee that the marked method is intrinsified by the HotSpot VM.
+ *
+ * If the {@code CheckIntrinsics} VM flag is enabled, the HotSpot VM checks
+ * (when loading a class) that (1) all methods of that class that are also on
+ * the VM's list of intrinsics are annotated with {@code @HotSpotIntrinsicCandidate}
+ * and that (2) for all methods of that class annotated with
+ * {@code @HotSpotIntrinsicCandidate} there is an intrinsic in the list.
+ *
+ * @since 9
+ */
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+// Android-changed: RetentionPolicy.SOURCE is sufficient as this is no-op on Android.
+// @Retention(RetentionPolicy.RUNTIME)
+@Retention(RetentionPolicy.SOURCE)
+public @interface HotSpotIntrinsicCandidate {
+}
diff --git a/ojluni/src/main/java/jdk/internal/misc/Unsafe.java b/ojluni/src/main/java/jdk/internal/misc/Unsafe.java
index c6a350b..c7ff084 100644
--- a/ojluni/src/main/java/jdk/internal/misc/Unsafe.java
+++ b/ojluni/src/main/java/jdk/internal/misc/Unsafe.java
@@ -26,6 +26,7 @@
 package jdk.internal.misc;
 
 import dalvik.annotation.optimization.FastNative;
+import jdk.internal.HotSpotIntrinsicCandidate;
 import sun.reflect.Reflection;
 
 import java.lang.reflect.Field;
@@ -129,6 +130,42 @@
         return getArrayBaseOffsetForComponentType(component);
     }
 
+    /** The value of {@code arrayBaseOffset(boolean[].class)} */
+    public static final int ARRAY_BOOLEAN_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(boolean[].class);
+
+    /** The value of {@code arrayBaseOffset(byte[].class)} */
+    public static final int ARRAY_BYTE_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(byte[].class);
+
+    /** The value of {@code arrayBaseOffset(short[].class)} */
+    public static final int ARRAY_SHORT_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(short[].class);
+
+    /** The value of {@code arrayBaseOffset(char[].class)} */
+    public static final int ARRAY_CHAR_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(char[].class);
+
+    /** The value of {@code arrayBaseOffset(int[].class)} */
+    public static final int ARRAY_INT_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(int[].class);
+
+    /** The value of {@code arrayBaseOffset(long[].class)} */
+    public static final int ARRAY_LONG_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(long[].class);
+
+    /** The value of {@code arrayBaseOffset(float[].class)} */
+    public static final int ARRAY_FLOAT_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(float[].class);
+
+    /** The value of {@code arrayBaseOffset(double[].class)} */
+    public static final int ARRAY_DOUBLE_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(double[].class);
+
+    /** The value of {@code arrayBaseOffset(Object[].class)} */
+    public static final int ARRAY_OBJECT_BASE_OFFSET
+            = theUnsafe.arrayBaseOffset(Object[].class);
+
     /**
      * Gets the size of each element of the given array class.
      *
@@ -143,12 +180,163 @@
       return getArrayIndexScaleForComponentType(component);
     }
 
+    /** The value of {@code arrayIndexScale(boolean[].class)} */
+    public static final int ARRAY_BOOLEAN_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(boolean[].class);
+
+    /** The value of {@code arrayIndexScale(byte[].class)} */
+    public static final int ARRAY_BYTE_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(byte[].class);
+
+    /** The value of {@code arrayIndexScale(short[].class)} */
+    public static final int ARRAY_SHORT_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(short[].class);
+
+    /** The value of {@code arrayIndexScale(char[].class)} */
+    public static final int ARRAY_CHAR_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(char[].class);
+
+    /** The value of {@code arrayIndexScale(int[].class)} */
+    public static final int ARRAY_INT_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(int[].class);
+
+    /** The value of {@code arrayIndexScale(long[].class)} */
+    public static final int ARRAY_LONG_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(long[].class);
+
+    /** The value of {@code arrayIndexScale(float[].class)} */
+    public static final int ARRAY_FLOAT_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(float[].class);
+
+    /** The value of {@code arrayIndexScale(double[].class)} */
+    public static final int ARRAY_DOUBLE_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(double[].class);
+
+    /** The value of {@code arrayIndexScale(Object[].class)} */
+    public static final int ARRAY_OBJECT_INDEX_SCALE
+            = theUnsafe.arrayIndexScale(Object[].class);
+
     @FastNative
     private static native int getArrayBaseOffsetForComponentType(Class component_class);
     @FastNative
     private static native int getArrayIndexScaleForComponentType(Class component_class);
 
     /**
+     * Fetches a value at some byte offset into a given Java object.
+     * More specifically, fetches a value within the given object
+     * <code>o</code> at the given offset, or (if <code>o</code> is
+     * null) from the memory address whose numerical value is the
+     * given offset.  <p>
+     *
+     * The specification of this method is the same as {@link
+     * #getLong(Object, long)} except that the offset does not need to
+     * have been obtained from {@link #objectFieldOffset} on the
+     * {@link java.lang.reflect.Field} of some Java field.  The value
+     * in memory is raw data, and need not correspond to any Java
+     * variable.  Unless <code>o</code> is null, the value accessed
+     * must be entirely within the allocated object.  The endianness
+     * of the value in memory is the endianness of the native platform.
+     *
+     * <p> The read will be atomic with respect to the largest power
+     * of two that divides the GCD of the offset and the storage size.
+     * For example, getLongUnaligned will make atomic reads of 2-, 4-,
+     * or 8-byte storage units if the offset is zero mod 2, 4, or 8,
+     * respectively.  There are no other guarantees of atomicity.
+     * <p>
+     * 8-byte atomicity is only guaranteed on platforms on which
+     * support atomic accesses to longs.
+     *
+     * @param o Java heap object in which the value resides, if any, else
+     *        null
+     * @param offset The offset in bytes from the start of the object
+     * @return the value fetched from the indicated object
+     * @throws RuntimeException No defined exceptions are thrown, not even
+     *         {@link NullPointerException}
+     * @since 9
+     */
+    public final long getLongUnaligned(Object o, long offset) {
+        if ((offset & 7) == 0) {
+            return getLong(o, offset);
+        } else if ((offset & 3) == 0) {
+            return makeLong(getInt(o, offset),
+                    getInt(o, offset + 4));
+        } else if ((offset & 1) == 0) {
+            return makeLong(getShort(o, offset),
+                    getShort(o, offset + 2),
+                    getShort(o, offset + 4),
+                    getShort(o, offset + 6));
+        } else {
+            return makeLong(getByte(o, offset),
+                    getByte(o, offset + 1),
+                    getByte(o, offset + 2),
+                    getByte(o, offset + 3),
+                    getByte(o, offset + 4),
+                    getByte(o, offset + 5),
+                    getByte(o, offset + 6),
+                    getByte(o, offset + 7));
+        }
+    }
+
+    /** @see #getLongUnaligned(Object, long) */
+    public final int getIntUnaligned(Object o, long offset) {
+        if ((offset & 3) == 0) {
+            return getInt(o, offset);
+        } else if ((offset & 1) == 0) {
+            return makeInt(getShort(o, offset),
+                    getShort(o, offset + 2));
+        } else {
+            return makeInt(getByte(o, offset),
+                    getByte(o, offset + 1),
+                    getByte(o, offset + 2),
+                    getByte(o, offset + 3));
+        }
+    }
+
+    // These methods construct integers from bytes.  The byte ordering
+    // is the native endianness of this platform.
+    private static long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
+        return ((toUnsignedLong(i0))
+                | (toUnsignedLong(i1) << 8)
+                | (toUnsignedLong(i2) << 16)
+                | (toUnsignedLong(i3) << 24)
+                | (toUnsignedLong(i4) << 32)
+                | (toUnsignedLong(i5) << 40)
+                | (toUnsignedLong(i6) << 48)
+                | (toUnsignedLong(i7) << 56));
+    }
+    private static long makeLong(short i0, short i1, short i2, short i3) {
+        return ((toUnsignedLong(i0))
+                | (toUnsignedLong(i1) << 16)
+                | (toUnsignedLong(i2) << 32)
+                | (toUnsignedLong(i3) << 48));
+    }
+    private static long makeLong(int i0, int i1) {
+        return (toUnsignedLong(i0))
+                | (toUnsignedLong(i1) << 32);
+    }
+    private static int makeInt(short i0, short i1) {
+        return (toUnsignedInt(i0))
+                | (toUnsignedInt(i1) << 16);
+    }
+    private static int makeInt(byte i0, byte i1, byte i2, byte i3) {
+        return ((toUnsignedInt(i0))
+                | (toUnsignedInt(i1) << 8)
+                | (toUnsignedInt(i2) << 16)
+                | (toUnsignedInt(i3) << 24));
+    }
+    private static short makeShort(byte i0, byte i1) {
+        return (short)((toUnsignedInt(i0))
+                | (toUnsignedInt(i1) << 8));
+    }
+
+    // Zero-extend an integer
+    private static int toUnsignedInt(byte n)    { return n & 0xff; }
+    private static int toUnsignedInt(short n)   { return n & 0xffff; }
+    private static long toUnsignedLong(byte n)  { return n & 0xffL; }
+    private static long toUnsignedLong(short n) { return n & 0xffffL; }
+    private static long toUnsignedLong(int n)   { return n & 0xffffffffL; }
+
+    /**
      * Performs a compare-and-set operation on an {@code int}
      * field within the given object.
      *
@@ -722,7 +910,7 @@
      *
      * @return {@code true} if successful
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public final native boolean compareAndSetInt(Object o, long offset,
                                                  int expected,
@@ -737,7 +925,7 @@
      *
      * @return {@code true} if successful
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public final native boolean compareAndSetLong(Object o, long offset,
                                                   long expected,
@@ -752,7 +940,7 @@
      *
      * @return {@code true} if successful
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public final native boolean compareAndSetObject(Object o, long offset,
                                                     Object expected,
@@ -772,7 +960,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final int getAndAddInt(Object o, long offset, int delta) {
         int v;
         do {
@@ -792,7 +980,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final long getAndAddLong(Object o, long offset, long delta) {
         long v;
         do {
@@ -812,7 +1000,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final int getAndSetInt(Object o, long offset, int newValue) {
         int v;
         do {
@@ -832,7 +1020,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final long getAndSetLong(Object o, long offset, long newValue) {
         long v;
         do {
@@ -852,7 +1040,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final Object getAndSetObject(Object o, long offset, Object newValue) {
         Object v;
         do {
@@ -862,37 +1050,37 @@
     }
 
     /** Release version of {@link #putIntVolatile(Object, long, int)} */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final void putIntRelease(Object o, long offset, int x) {
         putIntVolatile(o, offset, x);
     }
 
     /** Acquire version of {@link #getIntVolatile(Object, long)} */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final int getIntAcquire(Object o, long offset) {
         return getIntVolatile(o, offset);
     }
 
     /** Release version of {@link #putLongVolatile(Object, long, long)} */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final void putLongRelease(Object o, long offset, long x) {
         putLongVolatile(o, offset, x);
     }
 
     /** Acquire version of {@link #getLongVolatile(Object, long)} */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final long getLongAcquire(Object o, long offset) {
         return getLongVolatile(o, offset);
     }
 
     /** Release version of {@link #putObjectVolatile(Object, long, Object)} */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final void putObjectRelease(Object o, long offset, Object x) {
         putObjectVolatile(o, offset, x);
     }
 
     /** Acquire version of {@link #getObjectVolatile(Object, long)} */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final Object getObjectAcquire(Object o, long offset) {
         return getObjectVolatile(o, offset);
     }
@@ -909,7 +1097,7 @@
      * provide a LoadLoad barrier also provide a LoadStore barrier for free.
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public native void loadFence();
 
@@ -925,7 +1113,7 @@
      * provide a StoreStore barrier also provide a LoadStore barrier for free.
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public native void storeFence();
 
@@ -938,7 +1126,7 @@
      * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst).
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public native void fullFence();
 
diff --git a/ojluni/src/main/java/jdk/internal/util/ArraysSupport.java b/ojluni/src/main/java/jdk/internal/util/ArraysSupport.java
new file mode 100644
index 0000000..50ea4f0
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/util/ArraysSupport.java
@@ -0,0 +1,575 @@
+/*
+ * 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 jdk.internal.util;
+
+import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * Utility methods to find a mismatch between two primitive arrays.
+ *
+ * <p>Array equality and lexicographical comparison can be built on top of
+ * array mismatch functionality.
+ *
+ * <p>The mismatch method implementation, {@link #vectorizedMismatch}, leverages
+ * vector-based techniques to access and compare the contents of two arrays.
+ * The Java implementation uses {@code Unsafe.getLongUnaligned} to access the
+ * content of an array, thus access is supported on platforms that do not
+ * support unaligned access.  For a byte[] array, 8 bytes (64 bits) can be
+ * accessed and compared as a unit rather than individually, which increases
+ * the performance when the method is compiled by the HotSpot VM.  On supported
+ * platforms the mismatch implementation is intrinsified to leverage SIMD
+ * instructions.  So for a byte[] array, 16 bytes (128 bits), 32 bytes
+ * (256 bits), and perhaps in the future even 64 bytes (512 bits), platform
+ * permitting, can be accessed and compared as a unit, which further increases
+ * the performance over the Java implementation.
+ *
+ * <p>None of the mismatch methods perform array bounds checks.  It is the
+ * responsibility of the caller (direct or otherwise) to perform such checks
+ * before calling this method.
+ */
+public class ArraysSupport {
+    static final Unsafe U = Unsafe.getUnsafe();
+
+    // Android-changed: Android is little endian.
+    private static final boolean BIG_ENDIAN = false;
+
+    public static final int LOG2_ARRAY_BOOLEAN_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BOOLEAN_INDEX_SCALE);
+    public static final int LOG2_ARRAY_BYTE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BYTE_INDEX_SCALE);
+    public static final int LOG2_ARRAY_CHAR_INDEX_SCALE = exactLog2(Unsafe.ARRAY_CHAR_INDEX_SCALE);
+    public static final int LOG2_ARRAY_SHORT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_SHORT_INDEX_SCALE);
+    public static final int LOG2_ARRAY_INT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_INT_INDEX_SCALE);
+    public static final int LOG2_ARRAY_LONG_INDEX_SCALE = exactLog2(Unsafe.ARRAY_LONG_INDEX_SCALE);
+    public static final int LOG2_ARRAY_FLOAT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_FLOAT_INDEX_SCALE);
+    public static final int LOG2_ARRAY_DOUBLE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
+
+    private static final int LOG2_BYTE_BIT_SIZE = exactLog2(Byte.SIZE);
+
+    private static int exactLog2(int scale) {
+        if ((scale & (scale - 1)) != 0)
+            throw new Error("data type scale not a power of two");
+        return Integer.numberOfTrailingZeros(scale);
+    }
+
+    private ArraysSupport() {}
+
+    /**
+     * Find the relative index of the first mismatching pair of elements in two
+     * primitive arrays of the same component type.  Pairs of elements will be
+     * tested in order relative to given offsets into both arrays.
+     *
+     * <p>This method does not perform type checks or bounds checks.  It is the
+     * responsibility of the caller to perform such checks before calling this
+     * method.
+     *
+     * <p>The given offsets, in bytes, need not be aligned according to the
+     * given log<sub>2</sub> size the array elements.  More specifically, an
+     * offset modulus the size need not be zero.
+     *
+     * @param a the first array to be tested for mismatch, or {@code null} for
+     * direct memory access
+     * @param aOffset the relative offset, in bytes, from the base address of
+     * the first array to test from, otherwise if the first array is
+     * {@code null}, an absolute address pointing to the first element to test.
+     * @param b the second array to be tested for mismatch, or {@code null} for
+     * direct memory access
+     * @param bOffset the relative offset, in bytes, from the base address of
+     * the second array to test from, otherwise if the second array is
+     * {@code null}, an absolute address pointing to the first element to test.
+     * @param length the number of array elements to test
+     * @param log2ArrayIndexScale log<sub>2</sub> of the array index scale, that
+     * corresponds to the size, in bytes, of an array element.
+     * @return if a mismatch is found a relative index, between 0 (inclusive)
+     * and {@code length} (exclusive), of the first mismatching pair of elements
+     * in the two arrays.  Otherwise, if a mismatch is not found the bitwise
+     * compliment of the number of remaining pairs of elements to be checked in
+     * the tail of the two arrays.
+     */
+    @HotSpotIntrinsicCandidate
+    public static int vectorizedMismatch(Object a, long aOffset,
+                                         Object b, long bOffset,
+                                         int length,
+                                         int log2ArrayIndexScale) {
+        // assert a.getClass().isArray();
+        // assert b.getClass().isArray();
+        // assert 0 <= length <= sizeOf(a)
+        // assert 0 <= length <= sizeOf(b)
+        // assert 0 <= log2ArrayIndexScale <= 3
+
+        int log2ValuesPerWidth = LOG2_ARRAY_LONG_INDEX_SCALE - log2ArrayIndexScale;
+        int wi = 0;
+        for (; wi < length >> log2ValuesPerWidth; wi++) {
+            long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;
+            long av = U.getLongUnaligned(a, aOffset + bi);
+            long bv = U.getLongUnaligned(b, bOffset + bi);
+            if (av != bv) {
+                long x = av ^ bv;
+                int o = BIG_ENDIAN
+                        ? Long.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)
+                        : Long.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);
+                return (wi << log2ValuesPerWidth) + o;
+            }
+        }
+
+        // Calculate the tail of remaining elements to check
+        int tail = length - (wi << log2ValuesPerWidth);
+
+        if (log2ArrayIndexScale < LOG2_ARRAY_INT_INDEX_SCALE) {
+            int wordTail = 1 << (LOG2_ARRAY_INT_INDEX_SCALE - log2ArrayIndexScale);
+            // Handle 4 bytes or 2 chars in the tail using int width
+            if (tail >= wordTail) {
+                long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;
+                int av = U.getIntUnaligned(a, aOffset + bi);
+                int bv = U.getIntUnaligned(b, bOffset + bi);
+                if (av != bv) {
+                    int x = av ^ bv;
+                    int o = BIG_ENDIAN
+                            ? Integer.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)
+                            : Integer.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);
+                    return (wi << log2ValuesPerWidth) + o;
+                }
+                tail -= wordTail;
+            }
+            return ~tail;
+        }
+        else {
+            return ~tail;
+        }
+    }
+
+    // Booleans
+    // Each boolean element takes up one byte
+
+    public static int mismatch(boolean[] a,
+                               boolean[] b,
+                               int length) {
+        int i = 0;
+        if (length > 7) {
+            if (a[0] != b[0])
+                return 0;
+            i = vectorizedMismatch(
+                    a, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
+                    b, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
+                    length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[i] != b[i])
+                return i;
+        }
+        return -1;
+    }
+
+    public static int mismatch(boolean[] a, int aFromIndex,
+                               boolean[] b, int bFromIndex,
+                               int length) {
+        int i = 0;
+        if (length > 7) {
+            if (a[aFromIndex] != b[bFromIndex])
+                return 0;
+            int aOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + aFromIndex;
+            int bOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + bFromIndex;
+            i = vectorizedMismatch(
+                    a, aOffset,
+                    b, bOffset,
+                    length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[aFromIndex + i] != b[bFromIndex + i])
+                return i;
+        }
+        return -1;
+    }
+
+
+    // Bytes
+
+    /**
+     * Find the index of a mismatch between two arrays.
+     *
+     * <p>This method does not perform bounds checks. It is the responsibility
+     * of the caller to perform such bounds checks before calling this method.
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @param length the number of bytes from each array to check
+     * @return the index of a mismatch between the two arrays, otherwise -1 if
+     * no mismatch.  The index will be within the range of (inclusive) 0 to
+     * (exclusive) the smaller of the two array lengths.
+     */
+    public static int mismatch(byte[] a,
+                               byte[] b,
+                               int length) {
+        // ISSUE: defer to index receiving methods if performance is good
+        // assert length <= a.length
+        // assert length <= b.length
+
+        int i = 0;
+        if (length > 7) {
+            if (a[0] != b[0])
+                return 0;
+            i = vectorizedMismatch(
+                    a, Unsafe.ARRAY_BYTE_BASE_OFFSET,
+                    b, Unsafe.ARRAY_BYTE_BASE_OFFSET,
+                    length, LOG2_ARRAY_BYTE_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            // Align to tail
+            i = length - ~i;
+//            assert i >= 0 && i <= 7;
+        }
+        // Tail < 8 bytes
+        for (; i < length; i++) {
+            if (a[i] != b[i])
+                return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Find the relative index of a mismatch between two arrays starting from
+     * given indexes.
+     *
+     * <p>This method does not perform bounds checks. It is the responsibility
+     * of the caller to perform such bounds checks before calling this method.
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index of the first element (inclusive) in the first
+     * array to be compared
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index of the first element (inclusive) in the
+     * second array to be compared
+     * @param length the number of bytes from each array to check
+     * @return the relative index of a mismatch between the two arrays,
+     * otherwise -1 if no mismatch.  The index will be within the range of
+     * (inclusive) 0 to (exclusive) the smaller of the two array bounds.
+     */
+    public static int mismatch(byte[] a, int aFromIndex,
+                               byte[] b, int bFromIndex,
+                               int length) {
+        // assert 0 <= aFromIndex < a.length
+        // assert 0 <= aFromIndex + length <= a.length
+        // assert 0 <= bFromIndex < b.length
+        // assert 0 <= bFromIndex + length <= b.length
+        // assert length >= 0
+
+        int i = 0;
+        if (length > 7) {
+            if (a[aFromIndex] != b[bFromIndex])
+                return 0;
+            int aOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + aFromIndex;
+            int bOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + bFromIndex;
+            i = vectorizedMismatch(
+                    a, aOffset,
+                    b, bOffset,
+                    length, LOG2_ARRAY_BYTE_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[aFromIndex + i] != b[bFromIndex + i])
+                return i;
+        }
+        return -1;
+    }
+
+
+    // Chars
+
+    public static int mismatch(char[] a,
+                               char[] b,
+                               int length) {
+        int i = 0;
+        if (length > 3) {
+            if (a[0] != b[0])
+                return 0;
+            i = vectorizedMismatch(
+                    a, Unsafe.ARRAY_CHAR_BASE_OFFSET,
+                    b, Unsafe.ARRAY_CHAR_BASE_OFFSET,
+                    length, LOG2_ARRAY_CHAR_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[i] != b[i])
+                return i;
+        }
+        return -1;
+    }
+
+    public static int mismatch(char[] a, int aFromIndex,
+                               char[] b, int bFromIndex,
+                               int length) {
+        int i = 0;
+        if (length > 3) {
+            if (a[aFromIndex] != b[bFromIndex])
+                return 0;
+            int aOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
+            int bOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
+            i = vectorizedMismatch(
+                    a, aOffset,
+                    b, bOffset,
+                    length, LOG2_ARRAY_CHAR_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[aFromIndex + i] != b[bFromIndex + i])
+                return i;
+        }
+        return -1;
+    }
+
+
+    // Shorts
+
+    public static int mismatch(short[] a,
+                               short[] b,
+                               int length) {
+        int i = 0;
+        if (length > 3) {
+            if (a[0] != b[0])
+                return 0;
+            i = vectorizedMismatch(
+                    a, Unsafe.ARRAY_SHORT_BASE_OFFSET,
+                    b, Unsafe.ARRAY_SHORT_BASE_OFFSET,
+                    length, LOG2_ARRAY_SHORT_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[i] != b[i])
+                return i;
+        }
+        return -1;
+    }
+
+    public static int mismatch(short[] a, int aFromIndex,
+                               short[] b, int bFromIndex,
+                               int length) {
+        int i = 0;
+        if (length > 3) {
+            if (a[aFromIndex] != b[bFromIndex])
+                return 0;
+            int aOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
+            int bOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
+            i = vectorizedMismatch(
+                    a, aOffset,
+                    b, bOffset,
+                    length, LOG2_ARRAY_SHORT_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[aFromIndex + i] != b[bFromIndex + i])
+                return i;
+        }
+        return -1;
+    }
+
+
+    // Ints
+
+    public static int mismatch(int[] a,
+                               int[] b,
+                               int length) {
+        int i = 0;
+        if (length > 1) {
+            if (a[0] != b[0])
+                return 0;
+            i = vectorizedMismatch(
+                    a, Unsafe.ARRAY_INT_BASE_OFFSET,
+                    b, Unsafe.ARRAY_INT_BASE_OFFSET,
+                    length, LOG2_ARRAY_INT_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[i] != b[i])
+                return i;
+        }
+        return -1;
+    }
+
+    public static int mismatch(int[] a, int aFromIndex,
+                               int[] b, int bFromIndex,
+                               int length) {
+        int i = 0;
+        if (length > 1) {
+            if (a[aFromIndex] != b[bFromIndex])
+                return 0;
+            int aOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
+            int bOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
+            i = vectorizedMismatch(
+                    a, aOffset,
+                    b, bOffset,
+                    length, LOG2_ARRAY_INT_INDEX_SCALE);
+            if (i >= 0)
+                return i;
+            i = length - ~i;
+        }
+        for (; i < length; i++) {
+            if (a[aFromIndex + i] != b[bFromIndex + i])
+                return i;
+        }
+        return -1;
+    }
+
+
+    // Floats
+
+    public static int mismatch(float[] a,
+                               float[] b,
+                               int length) {
+        return mismatch(a, 0, b, 0, length);
+    }
+
+    public static int mismatch(float[] a, int aFromIndex,
+                               float[] b, int bFromIndex,
+                               int length) {
+        int i = 0;
+        if (length > 1) {
+            if (Float.floatToRawIntBits(a[aFromIndex]) == Float.floatToRawIntBits(b[bFromIndex])) {
+                int aOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
+                int bOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
+                i = vectorizedMismatch(
+                        a, aOffset,
+                        b, bOffset,
+                        length, LOG2_ARRAY_FLOAT_INDEX_SCALE);
+            }
+            // Mismatched
+            if (i >= 0) {
+                // Check if mismatch is not associated with two NaN values
+                if (!Float.isNaN(a[aFromIndex + i]) || !Float.isNaN(b[bFromIndex + i]))
+                    return i;
+
+                // Mismatch on two different NaN values that are normalized to match
+                // Fall back to slow mechanism
+                // ISSUE: Consider looping over vectorizedMismatch adjusting ranges
+                // However, requires that returned value be relative to input ranges
+                i++;
+            }
+            // Matched
+            else {
+                i = length - ~i;
+            }
+        }
+        for (; i < length; i++) {
+            if (Float.floatToIntBits(a[aFromIndex + i]) != Float.floatToIntBits(b[bFromIndex + i]))
+                return i;
+        }
+        return -1;
+    }
+
+    // 64 bit sizes
+
+    // Long
+
+    public static int mismatch(long[] a,
+                               long[] b,
+                               int length) {
+        if (length == 0) {
+            return -1;
+        }
+        if (a[0] != b[0])
+            return 0;
+        int i = vectorizedMismatch(
+                a, Unsafe.ARRAY_LONG_BASE_OFFSET,
+                b, Unsafe.ARRAY_LONG_BASE_OFFSET,
+                length, LOG2_ARRAY_LONG_INDEX_SCALE);
+        return i >= 0 ? i : -1;
+    }
+
+    public static int mismatch(long[] a, int aFromIndex,
+                               long[] b, int bFromIndex,
+                               int length) {
+        if (length == 0) {
+            return -1;
+        }
+        if (a[aFromIndex] != b[bFromIndex])
+            return 0;
+        int aOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);
+        int bOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);
+        int i = vectorizedMismatch(
+                a, aOffset,
+                b, bOffset,
+                length, LOG2_ARRAY_LONG_INDEX_SCALE);
+        return i >= 0 ? i : -1;
+    }
+
+
+    // Double
+
+    public static int mismatch(double[] a,
+                               double[] b,
+                               int length) {
+        return mismatch(a, 0, b, 0, length);
+    }
+
+    public static int mismatch(double[] a, int aFromIndex,
+                               double[] b, int bFromIndex,
+                               int length) {
+        if (length == 0) {
+            return -1;
+        }
+        int i = 0;
+        if (Double.doubleToRawLongBits(a[aFromIndex]) == Double.doubleToRawLongBits(b[bFromIndex])) {
+            int aOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);
+            int bOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);
+            i = vectorizedMismatch(
+                    a, aOffset,
+                    b, bOffset,
+                    length, LOG2_ARRAY_DOUBLE_INDEX_SCALE);
+        }
+        if (i >= 0) {
+            // Check if mismatch is not associated with two NaN values
+            if (!Double.isNaN(a[aFromIndex + i]) || !Double.isNaN(b[bFromIndex + i]))
+                return i;
+
+            // Mismatch on two different NaN values that are normalized to match
+            // Fall back to slow mechanism
+            // ISSUE: Consider looping over vectorizedMismatch adjusting ranges
+            // However, requires that returned value be relative to input ranges
+            i++;
+            for (; i < length; i++) {
+                if (Double.doubleToLongBits(a[aFromIndex + i]) != Double.doubleToLongBits(b[bFromIndex + i]))
+                    return i;
+            }
+        }
+
+        return -1;
+    }
+}
diff --git a/ojluni/src/main/java/jdk/internal/util/Preconditions.java b/ojluni/src/main/java/jdk/internal/util/Preconditions.java
index 0e91afd..cb1b748 100644
--- a/ojluni/src/main/java/jdk/internal/util/Preconditions.java
+++ b/ojluni/src/main/java/jdk/internal/util/Preconditions.java
@@ -24,6 +24,8 @@
  */
 package jdk.internal.util;
 
+import jdk.internal.HotSpotIntrinsicCandidate;
+
 import java.util.List;
 import java.util.function.BiFunction;
 import java.util.function.Function;
@@ -238,8 +240,7 @@
      * 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
+    @HotSpotIntrinsicCandidate
     public static <X extends RuntimeException>
     int checkIndex(int index, int length,
                    BiFunction<String, List<Integer>, X> oobef) {
diff --git a/ojluni/src/main/java/jdk/internal/vm/annotation/Contended.java b/ojluni/src/main/java/jdk/internal/vm/annotation/Contended.java
new file mode 100644
index 0000000..fd616cc
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/vm/annotation/Contended.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+// Android-note: Contended-specific implementation notes not relevant for Android.
+/**
+ * <p>An annotation expressing that objects and/or their fields are
+ * expected to encounter memory contention, generally in the form of
+ * "false sharing". This annotation serves as a hint that such objects
+ * and fields should reside in locations isolated from those of other
+ * objects or fields. Susceptibility to memory contention is a
+ * property of the intended usages of objects and fields, not their
+ * types or qualifiers. The effects of this annotation will nearly
+ * always add significant space overhead to objects. The use of
+ * {@code @Contended} is warranted only when the performance impact of
+ * this time/space tradeoff is intrinsically worthwhile; for example,
+ * in concurrent contexts in which each instance of the annotated
+ * class is often accessed by a different thread.
+ *
+ * <p>A {@code @Contended} field annotation may optionally include a
+ * <i>contention group</i> tag. A contention group defines a set of one
+ * or more fields that collectively must be isolated from all other
+ * contention groups. The fields in the same contention group may not be
+ * pairwise isolated. With no contention group tag (or with the default
+ * empty tag: "") each {@code @Contended} field resides in its own
+ * <i>distinct</i> and <i>anonymous</i> contention group.
+ *
+ * <p>When the annotation is used at the class level, the effect is
+ * equivalent to grouping all the declared fields not already having the
+ * {@code @Contended} annotation into the same anonymous group.
+ * With the class level annotation, implementations may choose different
+ * isolation techniques, such as isolating the entire object, rather than
+ * isolating distinct fields. A contention group tag has no meaning
+ * in a class level {@code @Contended} annotation, and is ignored.
+ *
+ * <p>The class level {@code @Contended} annotation is not inherited and has
+ * no effect on the fields declared in any sub-classes. The effects of all
+ * {@code @Contended} annotations, however, remain in force for all
+ * subclass instances, providing isolation of all the defined contention
+ * groups. Contention group tags are not inherited, and the same tag used
+ * in a superclass and subclass, represent distinct contention groups.
+ *
+ * @since 1.8
+ */
+// Android-changed: RetentionPolicy.SOURCE is sufficient as this is no-op on Android.
+// @Retention(RetentionPolicy.RUNTIME)
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.FIELD, ElementType.TYPE})
+public @interface Contended {
+
+    /**
+     * The (optional) contention group tag.
+     * This tag is only meaningful for field level annotations.
+     *
+     * @return contention group tag.
+     */
+    String value() default "";
+}
diff --git a/ojluni/src/main/java/jdk/internal/vm/annotation/ReservedStackAccess.java b/ojluni/src/main/java/jdk/internal/vm/annotation/ReservedStackAccess.java
new file mode 100644
index 0000000..91ea865
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/vm/annotation/ReservedStackAccess.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+// Android-note: ReservedStackAccess-specific implementation not available on Android.
+/**
+ * <p>An annotation expressing that a method is especially sensitive
+ * to stack overflows. This is a hint the JVM can use to grant access to
+ * extra stack space when executing this code if such feature is supported
+ * by the JVM. The JVM is free to ignore this annotation.
+ *
+ * A possible way for the JVM to improve the execution context for methods
+ * with this annotation is to reserve part of the thread's execution stack
+ * for them. Access to this section of the stack would be denied by default
+ * but could be granted if the JVM detects a possible stack overflow and
+ * the thread's call stack includes at least one annotated method. Even if
+ * access to this reserved area has been granted, the JVM might decide to
+ * throw a delayed StackOverflowError when the thread exits the annotated
+ * method.
+ *
+ * @since 9
+ */
+// Android-changed: RetentionPolicy.SOURCE is sufficient as this is no-op on Android.
+// @Retention(RetentionPolicy.RUNTIME)
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface ReservedStackAccess { }
+
diff --git a/ojluni/src/main/java/sun/misc/Unsafe.java b/ojluni/src/main/java/sun/misc/Unsafe.java
index e538b73..59d8df5 100644
--- a/ojluni/src/main/java/sun/misc/Unsafe.java
+++ b/ojluni/src/main/java/sun/misc/Unsafe.java
@@ -26,6 +26,7 @@
 package sun.misc;
 
 import dalvik.annotation.optimization.FastNative;
+import jdk.internal.HotSpotIntrinsicCandidate;
 import sun.reflect.Reflection;
 
 import java.lang.reflect.Field;
@@ -698,7 +699,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final int getAndAddInt(Object o, long offset, int delta) {
         int v;
         do {
@@ -718,7 +719,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final long getAndAddLong(Object o, long offset, long delta) {
         long v;
         do {
@@ -738,7 +739,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final int getAndSetInt(Object o, long offset, int newValue) {
         int v;
         do {
@@ -758,7 +759,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final long getAndSetLong(Object o, long offset, long newValue) {
         long v;
         do {
@@ -778,7 +779,7 @@
      * @return the previous value
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     public final Object getAndSetObject(Object o, long offset, Object newValue) {
         Object v;
         do {
@@ -800,7 +801,7 @@
      * provide a LoadLoad barrier also provide a LoadStore barrier for free.
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public native void loadFence();
 
@@ -816,7 +817,7 @@
      * provide a StoreStore barrier also provide a LoadStore barrier for free.
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public native void storeFence();
 
@@ -829,7 +830,7 @@
      * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst).
      * @since 1.8
      */
-    // @HotSpotIntrinsicCandidate
+    @HotSpotIntrinsicCandidate
     @FastNative
     public native void fullFence();
 }
diff --git a/ojluni/src/main/java/sun/security/util/HexDumpEncoder.java b/ojluni/src/main/java/sun/security/util/HexDumpEncoder.java
new file mode 100644
index 0000000..9726a4f
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/util/HexDumpEncoder.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package sun.security.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * This class encodes a buffer into the classic: "Hexadecimal Dump" format of
+ * the past. It is useful for analyzing the contents of binary buffers.
+ * The format produced is as follows:
+ * <pre>
+ * xxxx: 00 11 22 33 44 55 66 77   88 99 aa bb cc dd ee ff ................
+ * </pre>
+ * Where xxxx is the offset into the buffer in 16 byte chunks, followed
+ * by ascii coded hexadecimal bytes followed by the ASCII representation of
+ * the bytes or '.' if they are not valid bytes.
+ *
+ * @author      Chuck McManis
+ */
+
+public class HexDumpEncoder {
+
+    private int offset;
+    private int thisLineLength;
+    private int currentByte;
+    private byte thisLine[] = new byte[16];
+
+    static void hexDigit(PrintStream p, byte x) {
+        char c;
+
+        c = (char) ((x >> 4) & 0xf);
+        if (c > 9)
+            c = (char) ((c-10) + 'A');
+        else
+            c = (char)(c + '0');
+        p.write(c);
+        c = (char) (x & 0xf);
+        if (c > 9)
+            c = (char)((c-10) + 'A');
+        else
+            c = (char)(c + '0');
+        p.write(c);
+    }
+
+    protected int bytesPerAtom() {
+        return (1);
+    }
+
+    protected int bytesPerLine() {
+        return (16);
+    }
+
+    protected void encodeBufferPrefix(OutputStream o) throws IOException {
+        offset = 0;
+        pStream = new PrintStream(o);
+    }
+
+    protected void encodeLinePrefix(OutputStream o, int len) throws IOException {
+        hexDigit(pStream, (byte)((offset >>> 8) & 0xff));
+        hexDigit(pStream, (byte)(offset & 0xff));
+        pStream.print(": ");
+        currentByte = 0;
+        thisLineLength = len;
+    }
+
+    protected void encodeAtom(OutputStream o, byte buf[], int off, int len) throws IOException {
+        thisLine[currentByte] = buf[off];
+        hexDigit(pStream, buf[off]);
+        pStream.print(" ");
+        currentByte++;
+        if (currentByte == 8)
+            pStream.print("  ");
+    }
+
+    protected void encodeLineSuffix(OutputStream o) throws IOException {
+        if (thisLineLength < 16) {
+            for (int i = thisLineLength; i < 16; i++) {
+                pStream.print("   ");
+                if (i == 7)
+                    pStream.print("  ");
+            }
+        }
+        pStream.print(" ");
+        for (int i = 0; i < thisLineLength; i++) {
+            if ((thisLine[i] < ' ') || (thisLine[i] > 'z')) {
+                pStream.print(".");
+            } else {
+                pStream.write(thisLine[i]);
+            }
+        }
+        pStream.println();
+        offset += thisLineLength;
+    }
+
+    /** Stream that understands "printing" */
+    protected PrintStream pStream;
+
+    /**
+     * This method works around the bizarre semantics of BufferedInputStream's
+     * read method.
+     */
+    protected int readFully(InputStream in, byte buffer[])
+            throws java.io.IOException {
+        for (int i = 0; i < buffer.length; i++) {
+            int q = in.read();
+            if (q == -1)
+                return i;
+            buffer[i] = (byte)q;
+        }
+        return buffer.length;
+    }
+
+    /**
+     * Encode bytes from the input stream, and write them as text characters
+     * to the output stream. This method will run until it exhausts the
+     * input stream, but does not print the line suffix for a final
+     * line that is shorter than bytesPerLine().
+     */
+    public void encode(InputStream inStream, OutputStream outStream)
+        throws IOException
+    {
+        int     j;
+        int     numBytes;
+        byte    tmpbuffer[] = new byte[bytesPerLine()];
+
+        encodeBufferPrefix(outStream);
+
+        while (true) {
+            numBytes = readFully(inStream, tmpbuffer);
+            if (numBytes == 0) {
+                break;
+            }
+            encodeLinePrefix(outStream, numBytes);
+            for (j = 0; j < numBytes; j += bytesPerAtom()) {
+
+                if ((j + bytesPerAtom()) <= numBytes) {
+                    encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
+                } else {
+                    encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
+                }
+            }
+            if (numBytes < bytesPerLine()) {
+                break;
+            } else {
+                encodeLineSuffix(outStream);
+            }
+        }
+    }
+
+    /**
+     * A 'streamless' version of encode that simply takes a buffer of
+     * bytes and returns a string containing the encoded buffer.
+     */
+    public String encode(byte aBuffer[]) {
+        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+        ByteArrayInputStream    inStream = new ByteArrayInputStream(aBuffer);
+        String retVal = null;
+        try {
+            encode(inStream, outStream);
+            // explicit ascii->unicode conversion
+            retVal = outStream.toString("ISO-8859-1");
+        } catch (Exception IOException) {
+            // This should never happen.
+            throw new Error("CharacterEncoder.encode internal error");
+        }
+        return (retVal);
+    }
+
+    /**
+     * Return a byte array from the remaining bytes in this ByteBuffer.
+     * <P>
+     * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+     * <P>
+     * To avoid an extra copy, the implementation will attempt to return the
+     * byte array backing the ByteBuffer.  If this is not possible, a
+     * new byte array will be created.
+     */
+    private byte [] getBytes(ByteBuffer bb) {
+        /*
+         * This should never return a BufferOverflowException, as we're
+         * careful to allocate just the right amount.
+         */
+        byte [] buf = null;
+
+        /*
+         * If it has a usable backing byte buffer, use it.  Use only
+         * if the array exactly represents the current ByteBuffer.
+         */
+        if (bb.hasArray()) {
+            byte [] tmp = bb.array();
+            if ((tmp.length == bb.capacity()) &&
+                    (tmp.length == bb.remaining())) {
+                buf = tmp;
+                bb.position(bb.limit());
+            }
+        }
+
+        if (buf == null) {
+            /*
+             * This class doesn't have a concept of encode(buf, len, off),
+             * so if we have a partial buffer, we must reallocate
+             * space.
+             */
+            buf = new byte[bb.remaining()];
+
+            /*
+             * position() automatically updated
+             */
+            bb.get(buf);
+        }
+
+        return buf;
+    }
+
+    /**
+     * A 'streamless' version of encode that simply takes a ByteBuffer
+     * and returns a string containing the encoded buffer.
+     * <P>
+     * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+     */
+    public String encode(ByteBuffer aBuffer) {
+        byte [] buf = getBytes(aBuffer);
+        return encode(buf);
+    }
+
+    /**
+     * Encode bytes from the input stream, and write them as text characters
+     * to the output stream. This method will run until it exhausts the
+     * input stream. It differs from encode in that it will add the
+     * line at the end of a final line that is shorter than bytesPerLine().
+     */
+    public void encodeBuffer(InputStream inStream, OutputStream outStream)
+        throws IOException
+    {
+        int     j;
+        int     numBytes;
+        byte    tmpbuffer[] = new byte[bytesPerLine()];
+
+        encodeBufferPrefix(outStream);
+
+        while (true) {
+            numBytes = readFully(inStream, tmpbuffer);
+            if (numBytes == 0) {
+                break;
+            }
+            encodeLinePrefix(outStream, numBytes);
+            for (j = 0; j < numBytes; j += bytesPerAtom()) {
+                if ((j + bytesPerAtom()) <= numBytes) {
+                    encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
+                } else {
+                    encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
+                }
+            }
+            encodeLineSuffix(outStream);
+            if (numBytes < bytesPerLine()) {
+                break;
+            }
+        }
+    }
+
+    /**
+     * Encode the buffer in <i>aBuffer</i> and write the encoded
+     * result to the OutputStream <i>aStream</i>.
+     */
+    public void encodeBuffer(byte aBuffer[], OutputStream aStream)
+        throws IOException
+    {
+        ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+        encodeBuffer(inStream, aStream);
+    }
+
+    /**
+     * A 'streamless' version of encode that simply takes a buffer of
+     * bytes and returns a string containing the encoded buffer.
+     */
+    public String encodeBuffer(byte aBuffer[]) {
+        ByteArrayOutputStream   outStream = new ByteArrayOutputStream();
+        ByteArrayInputStream    inStream = new ByteArrayInputStream(aBuffer);
+        try {
+            encodeBuffer(inStream, outStream);
+        } catch (Exception IOException) {
+            // This should never happen.
+            throw new Error("CharacterEncoder.encodeBuffer internal error");
+        }
+        return (outStream.toString());
+    }
+
+    /**
+     * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
+     * result to the OutputStream <i>aStream</i>.
+     * <P>
+     * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+     */
+    public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream)
+        throws IOException
+    {
+        byte [] buf = getBytes(aBuffer);
+        encodeBuffer(buf, aStream);
+    }
+
+}
diff --git a/ojluni/src/main/native/zip_util.c b/ojluni/src/main/native/zip_util.c
index 85ea608..01dcce7 100644
--- a/ojluni/src/main/native/zip_util.c
+++ b/ojluni/src/main/native/zip_util.c
@@ -775,7 +775,7 @@
     jzfile *zip = NULL;
 
     /* Clear zip error message */
-    // BEGIN: Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
+    // BEGIN Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
     /*
     if (pmsg != 0) {
         *pmsg = NULL;
@@ -806,7 +806,7 @@
     } else {
       *pmsg = localPmsg;
     }
-    // END: Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
+    // END Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
     return zip;
 }
 
diff --git a/ojluni/src/test/java/io/ByteArrayOutputStream/EncodingTest.java b/ojluni/src/test/java/io/ByteArrayOutputStream/EncodingTest.java
new file mode 100644
index 0000000..34a6b73
--- /dev/null
+++ b/ojluni/src/test/java/io/ByteArrayOutputStream/EncodingTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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 test.java.io.ByteArrayOutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183743
+ * @summary Test to verify the new overload method with Charset functions the same
+ * as the existing method that takes a charset name.
+ * @run testng EncodingTest
+ */
+public class EncodingTest {
+    /*
+     * DataProvider for the toString method test. Provides the following fields:
+     * byte array, charset name string, charset object
+     */
+    @DataProvider(name = "parameters")
+    public Object[][] getParameters() throws IOException {
+        byte[] data = getData();
+        return new Object[][]{
+                {data, StandardCharsets.UTF_8.name(), StandardCharsets.UTF_8},
+                {data, StandardCharsets.ISO_8859_1.name(), StandardCharsets.ISO_8859_1},
+        };
+    }
+
+    /**
+     * Verifies that the new overload method that takes a Charset is equivalent to
+     * the existing one that takes a charset name.
+     * @param data a byte array
+     * @param csn the charset name
+     * @param charset the charset
+     * @throws Exception if the test fails
+     */
+    @Test(dataProvider = "parameters")
+    public void test(byte[] data, String csn, Charset charset) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        baos.write(data);
+        String str1 = baos.toString(csn);
+        String str2 = baos.toString(charset);
+        Assert.assertEquals(str1, str2);
+    }
+
+    /*
+     * Returns an array containing a character that's invalid for UTF-8
+     * but valid for ISO-8859-1
+     */
+    byte[] getData() throws IOException {
+        String str1 = "A string that contains ";
+        String str2 = " , an invalid character for UTF-8.";
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        baos.write(str1.getBytes());
+        baos.write(0xFA);
+        baos.write(str2.getBytes());
+        return baos.toByteArray();
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/FileReader/ConstructorTest.java b/ojluni/src/test/java/io/FileReader/ConstructorTest.java
new file mode 100644
index 0000000..30b5504
--- /dev/null
+++ b/ojluni/src/test/java/io/FileReader/ConstructorTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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 test.java.io.FileReader;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183554
+ * @summary Test to verify the new Constructors that take a Charset.
+ * @run testng ConstructorTest
+ */
+public class ConstructorTest {
+    static String USER_DIR = System.getProperty("user.dir", ".");
+
+    public static enum ConstructorType {
+        STRING,
+        FILE
+    }
+
+    static final String TEST_STRING = "abc \u0100 \u0101 \u0555 \u07FD \u07FF";
+    static final int BUFFER_SIZE = 8192;
+
+    @DataProvider(name = "parameters")
+    public Object[][] getParameters() throws IOException {
+        File file1 = new File(USER_DIR, "FileReaderTest1.txt");
+        File file2 = new File(USER_DIR, "FileReaderTest2.txt");
+
+        return new Object[][]{
+                {ConstructorType.STRING, file1, file2, StandardCharsets.UTF_8},
+                {ConstructorType.FILE, file1, file2, StandardCharsets.UTF_8},
+                {ConstructorType.STRING, file1, file2, StandardCharsets.ISO_8859_1},
+                {ConstructorType.FILE, file1, file2, StandardCharsets.ISO_8859_1},
+        };
+    }
+
+    /**
+     * Verifies that the new constructors that take a Charset function the same
+     * as an InputStreamReader on a FileInputStream as was recommended before
+     * this change.
+     *
+     * @param type the type of the constructor
+     * @param file1 file1 to be read with a FileReader
+     * @param file2 file2 to be read with an InputStreamReader
+     * @param charset the charset
+     * @throws IOException
+     */
+    @Test(dataProvider = "parameters")
+    void test(ConstructorType type, File file1, File file2, Charset charset)
+            throws Exception {
+        prepareFile(file1, TEST_STRING, charset);
+        prepareFile(file2, TEST_STRING, charset);
+
+        try (FileReader fr = getFileReader(type, file1, charset);
+             FileInputStream is = new FileInputStream(file2);
+             InputStreamReader isr = new InputStreamReader(is, charset);) {
+            String result1 = readAll(fr, BUFFER_SIZE);
+            String result2 = readAll(isr, BUFFER_SIZE);
+            Assert.assertEquals(result1, result2);
+        }
+    }
+
+    public String readAll(Reader reader, int bufferSize) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        char[] buf = new char[bufferSize];
+        int numRead;
+        while ((numRead = reader.read(buf)) != -1) {
+            if (numRead == buf.length) {
+                sb.append(buf);
+            } else {
+                sb.append(String.valueOf(buf, 0, numRead));
+            }
+        }
+        return sb.toString();
+    }
+
+    /*
+     * Creates a FileReader over the given input file.
+     */
+    FileReader getFileReader(ConstructorType type, File file, Charset charset)
+            throws IOException {
+        switch (type) {
+            case STRING:
+                return new FileReader(file.getPath(), charset);
+            case FILE:
+                return new FileReader(file, charset);
+        }
+
+        return null;
+    }
+
+    void prepareFile(File file, String content, Charset charset) throws IOException {
+        try (FileWriter writer = new FileWriter(file, charset);) {
+            writer.write(content);
+        }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/FileWriter/ConstructorTest.java b/ojluni/src/test/java/io/FileWriter/ConstructorTest.java
new file mode 100644
index 0000000..c95ba89
--- /dev/null
+++ b/ojluni/src/test/java/io/FileWriter/ConstructorTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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 test.java.io.FileWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183554
+ * @summary Test to verify the new Constructors that take a Charset.
+ * @run testng ConstructorTest
+ */
+public class ConstructorTest {
+
+    public static enum ConstructorType {
+        STRING,
+        FILE,
+        STRING_APPEND,
+        FILE_APPEND
+    }
+
+    static final String TEST_STRING = "abc \u0100 \u0101 \u0555 \u07FD \u07FF";
+    static final int BUFFER_SIZE = 8192;
+
+    @DataProvider(name = "parameters")
+    public Object[][] getParameters() throws IOException {
+        File file1 = File.createTempFile("FileWriterTest1", "txt");
+        File file2 = File.createTempFile("FileWriterTest2", "txt");
+
+        return new Object[][]{
+                {ConstructorType.STRING, file1, file2, StandardCharsets.UTF_8},
+                {ConstructorType.FILE, file1, file2, StandardCharsets.UTF_8},
+                {ConstructorType.STRING_APPEND, file1, file2, StandardCharsets.UTF_8},
+                {ConstructorType.FILE_APPEND, file1, file2, StandardCharsets.UTF_8},
+                {ConstructorType.STRING, file1, file2, StandardCharsets.ISO_8859_1},
+                {ConstructorType.FILE, file1, file2, StandardCharsets.ISO_8859_1},
+                {ConstructorType.STRING_APPEND, file1, file2, StandardCharsets.ISO_8859_1},
+                {ConstructorType.FILE_APPEND, file1, file2, StandardCharsets.ISO_8859_1},
+        };
+    }
+
+    /**
+     * Verifies that the new constructors that take a Charset function the same
+     * as an OutputStreamWriter on a FileOutputStream as was recommended before
+     * this change.
+     *
+     * @param type the type of the constructor
+     * @param file1 file1 to be written with a FileWriter
+     * @param file2 file2 to be written  with an OutputStreamWriter
+     * @param charset the charset
+     * @throws IOException
+     */
+    @Test(dataProvider = "parameters")
+    void test(ConstructorType type, File file1, File file2, Charset charset)
+            throws Exception {
+        writeWithFileWriter(type, file1, TEST_STRING, charset);
+        writeWithOutputStreamWriter(type, file2, TEST_STRING, charset);
+
+        try (
+                FileReader r1 = getFileReader(type, file1, charset);
+                FileReader r2 = getFileReader(type, file2, charset);
+        ) {
+            String result1 = readAll(r1, BUFFER_SIZE);
+            String result2 = readAll(r2, BUFFER_SIZE);
+            Assert.assertEquals(result1, result2);
+        }
+    }
+
+    public String readAll(Reader reader, int bufferSize) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        char[] buf = new char[bufferSize];
+        int numRead;
+        while ((numRead = reader.read(buf)) != -1) {
+            if (numRead == buf.length) {
+                sb.append(buf);
+            } else {
+                sb.append(String.valueOf(buf, 0, numRead));
+            }
+        }
+        return sb.toString();
+    }
+
+    /*
+     * Creates a FileReader over the given input file.
+     */
+    FileReader getFileReader(ConstructorType type, File file, Charset charset)
+            throws IOException {
+        switch (type) {
+            case STRING:
+            case STRING_APPEND:
+                return new FileReader(file.getPath(), charset);
+            case FILE:
+            case FILE_APPEND:
+                return new FileReader(file, charset);
+        }
+
+        return null;
+    }
+
+    /*
+     * Creates a FileWriter using the constructor as specified.
+     */
+    FileWriter getFileWriter(ConstructorType type, File file, Charset charset)
+            throws IOException {
+        switch (type) {
+            case STRING:
+                return new FileWriter(file.getPath(), charset);
+            case FILE:
+                return new FileWriter(file, charset);
+            case STRING_APPEND:
+                return new FileWriter(file.getPath(), charset, true);
+            case FILE_APPEND:
+                return new FileWriter(file, charset, true);
+        }
+
+        return null;
+    }
+
+    void writeWithFileWriter(ConstructorType type, File file, String content, Charset charset)
+            throws IOException {
+        if (type == ConstructorType.STRING_APPEND || type == ConstructorType.FILE_APPEND) {
+            try (FileWriter writer = getFileWriter(ConstructorType.FILE, file, charset);) {
+                writer.write(content);
+            }
+        }
+        try (FileWriter writer = getFileWriter(type, file, charset);) {
+            writer.write(content);
+        }
+    }
+
+    void writeWithOutputStreamWriter(ConstructorType type, File file, String content, Charset charset)
+            throws IOException {
+        try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), charset)) {
+            writer.write(content);
+            if (type == ConstructorType.STRING_APPEND || type == ConstructorType.FILE_APPEND) {
+                writer.write(content);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/PrintStream/EncodingTest.java b/ojluni/src/test/java/io/PrintStream/EncodingTest.java
new file mode 100644
index 0000000..41caec7
--- /dev/null
+++ b/ojluni/src/test/java/io/PrintStream/EncodingTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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 test.java.io.PrintStream;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183743
+ * @summary Test to verify the new overload method with Charset functions the same
+ * as the existing method that takes a charset name.
+ * @run testng EncodingTest
+ */
+public class EncodingTest {
+    static boolean AUTOFLUSH = true;
+    public static enum ConstructorType {
+        STRING,
+        FILE,
+        OUTPUTSTREAM
+    }
+
+    /*
+     * DataProvider fields:
+     * Type of the constructor, a file to be written with a charset name,
+     * a file to be written with a charset, charset name, charset.
+     */
+    @DataProvider(name = "parameters")
+    public Object[][] getParameters() throws IOException {
+        String csn = StandardCharsets.UTF_8.name();
+        Charset charset = StandardCharsets.UTF_8;
+        File file1 = File.createTempFile("PSCharsetTest1", "txt");
+        File file2 = File.createTempFile("PSCharsetTest2", "txt");
+
+        return new Object[][]{
+                {ConstructorType.STRING, file1, file2, csn, charset},
+                {ConstructorType.FILE, file1, file2, csn, charset},
+                {ConstructorType.OUTPUTSTREAM, file1, file2, csn, charset}
+        };
+    }
+
+    /**
+     * Verifies that the overloading constructor behaves the same as the existing
+     * one.
+     * @param type the type of the constructor
+     * @param file1 file1 written with the name of a charset
+     * @param file2 file2 written with a charset
+     * @param csn the charset name
+     * @param charset the charset
+     * @throws IOException
+     */
+    @Test(dataProvider = "parameters")
+    public void test(ConstructorType type, File file1, File file2, String csn, Charset charset)
+            throws Exception {
+        createFile(getPrintStream(type, file1.getPath(), csn, null));
+        createFile(getPrintStream(type, file2.getPath(), null, charset));
+
+        Assert.assertEquals(Files.readAllLines(Paths.get(file1.getPath()), charset),
+                Files.readAllLines(Paths.get(file2.getPath()), charset));
+    }
+
+    public void createFile(PrintStream out) throws IOException {
+        out.println("high surrogate");
+        out.println(Character.MIN_HIGH_SURROGATE);
+        out.println("low surrogate");
+        out.println(Character.MIN_LOW_SURROGATE);
+        out.flush();
+        out.close();
+    }
+
+    PrintStream getPrintStream(ConstructorType type, String path, String csn, Charset charset)
+            throws IOException {
+        PrintStream out = null;
+        if (csn != null) {
+            switch (type) {
+                case STRING:
+                    out = new PrintStream(path, csn);
+                    break;
+                case FILE:
+                    out = new PrintStream(new File(path), csn);
+                    break;
+                case OUTPUTSTREAM:
+                    FileOutputStream fout = new FileOutputStream(path);
+                    out = new PrintStream(fout, AUTOFLUSH, csn);
+                    break;
+            }
+        } else {
+            switch (type) {
+                case STRING:
+                    out = new PrintStream(path, charset);
+                    break;
+                case FILE:
+                    out = new PrintStream(new File(path), charset);
+                    break;
+                case OUTPUTSTREAM:
+                    FileOutputStream fout = new FileOutputStream(path);
+                    out = new PrintStream(fout, AUTOFLUSH, charset);
+                    break;
+            }
+        }
+
+        return out;
+    }
+
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/PrintWriter/EncodingTest.java b/ojluni/src/test/java/io/PrintWriter/EncodingTest.java
new file mode 100644
index 0000000..7f2608b
--- /dev/null
+++ b/ojluni/src/test/java/io/PrintWriter/EncodingTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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 test.java.io.PrintWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183743
+ * @bug 8183743
+ * @summary Test to verify the new overload method with Charset functions the same
+ * as the existing method that takes a charset name.
+ * @run testng EncodingTest
+ */
+public class EncodingTest {
+    static boolean AUTOFLUSH = true;
+    public static enum ConstructorType {
+        STRING,
+        FILE,
+        OUTPUTSTREAM
+    }
+
+    /*
+     * DataProvider fields:
+     * Type of the constructor, a file to be written with a charset name,
+     * a file to be written with a charset, charset name, charset.
+     */
+    @DataProvider(name = "parameters")
+    public Object[][] getParameters() throws IOException {
+        String csn = StandardCharsets.UTF_8.name();
+        Charset charset = StandardCharsets.UTF_8;
+        File file1 = File.createTempFile("PSCharsetTest1", "txt");
+        File file2 = File.createTempFile("PSCharsetTest2", "txt");
+
+        return new Object[][]{
+                {ConstructorType.STRING, file1, file2, csn, charset},
+                {ConstructorType.FILE, file1, file2, csn, charset},
+                {ConstructorType.OUTPUTSTREAM, file1, file2, csn, charset}
+        };
+    }
+
+    /**
+     * Verifies that the overloading constructor behaves the same as the existing
+     * one.
+     *
+     * @param type the type of the constructor
+     * @param file1 file1 written with the name of a charset
+     * @param file2 file2 written with a charset
+     * @param csn the charset name
+     * @param charset the charset
+     * @throws IOException
+     */
+    @Test(dataProvider = "parameters")
+    public void test(ConstructorType type, File file1, File file2, String csn, Charset charset)
+            throws Exception {
+        createFile(getWriter(type, file1.getPath(), csn, null));
+        createFile(getWriter(type, file2.getPath(), null, charset));
+
+        Assert.assertEquals(Files.readAllLines(Paths.get(file1.getPath()), charset),
+                Files.readAllLines(Paths.get(file2.getPath()), charset));
+    }
+
+    void createFile(PrintWriter out) throws IOException {
+        out.println("high surrogate");
+        out.println(Character.MIN_HIGH_SURROGATE);
+        out.println("low surrogate");
+        out.println(Character.MIN_LOW_SURROGATE);
+        out.flush();
+        out.close();
+    }
+
+    PrintWriter getWriter(ConstructorType type, String path, String csn, Charset charset)
+            throws IOException {
+        PrintWriter out = null;
+        if (csn != null) {
+            switch (type) {
+                case STRING:
+                    out = new PrintWriter(path, csn);
+                    break;
+                case FILE:
+                    out = new PrintWriter(new File(path), csn);
+                    break;
+                case OUTPUTSTREAM:
+                    // No corresponding method with charset name
+                    // compare with PrintWriter(path, csn) instead
+                    out = new PrintWriter(path, csn);
+                    break;
+            }
+        } else {
+            switch (type) {
+                case STRING:
+                    out = new PrintWriter(path, charset);
+                    break;
+                case FILE:
+                    out = new PrintWriter(new File(path), charset);
+                    break;
+                case OUTPUTSTREAM:
+                    FileOutputStream fout = new FileOutputStream(path);
+                    out = new PrintWriter(fout, AUTOFLUSH, charset);
+                    break;
+            }
+        }
+
+        return out;
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/Reader/NullReader.java b/ojluni/src/test/java/io/Reader/NullReader.java
new file mode 100644
index 0000000..67083f1
--- /dev/null
+++ b/ojluni/src/test/java/io/Reader/NullReader.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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 test.java.io.Reader;
+
+import java.io.Reader;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.CharBuffer;
+import java.nio.ReadOnlyBufferException;
+
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @bug 8196298 8204930
+ * @run testng NullReader
+ * @summary Check for expected behavior of Reader.nullReader().
+ */
+public class NullReader {
+    private static Reader openReader;
+    private static Reader closedReader;
+
+    @BeforeGroups(groups = "open")
+    public static void openStream() {
+        openReader = Reader.nullReader();
+    }
+
+    @BeforeGroups(groups = "closed")
+    public static void openAndCloseStream() throws IOException {
+        closedReader = Reader.nullReader();
+        closedReader.close();
+    }
+
+    @AfterGroups(groups = "open")
+    public static void closeStream() throws IOException {
+        openReader.close();
+    }
+
+    @Test(groups = "open")
+    public static void testOpen() {
+        assertNotNull(openReader, "Reader.nullReader() returned null");
+    }
+
+    @Test(groups = "open")
+    public static void testRead() throws IOException {
+        assertEquals(-1, openReader.read(), "read() != -1");
+    }
+
+    @Test(groups = "open")
+    public static void testReadBII() throws IOException {
+        assertEquals(-1, openReader.read(new char[1], 0, 1),
+                "read(char[],int,int) != -1");
+    }
+
+    @Test(groups = "open")
+    public static void testReadBIILenZero() throws IOException {
+        assertEquals(0, openReader.read(new char[1], 0, 0),
+                "read(char[],int,int) != 0");
+    }
+
+    @Test(groups = "open")
+    public static void testReadCharBuffer() throws IOException {
+        CharBuffer charBuffer = CharBuffer.allocate(1);
+        assertEquals(-1, openReader.read(charBuffer),
+                "read(CharBuffer) != -1");
+    }
+
+    @Test(groups = "open")
+    public static void testReadCharBufferZeroRemaining() throws IOException {
+        CharBuffer charBuffer = CharBuffer.allocate(0);
+        assertEquals(0, openReader.read(charBuffer),
+                "read(CharBuffer) != 0");
+    }
+
+    @Test(groups = "open")
+    public static void testReady() throws IOException {
+        assertFalse(openReader.ready());
+    }
+
+    @Test(groups = "open")
+    public static void testSkip() throws IOException {
+        assertEquals(0, openReader.skip(1), "skip() != 0");
+    }
+
+    @Test(groups = "open")
+    public static void testTransferTo() throws IOException {
+        assertEquals(0, openReader.transferTo(new StringWriter(7)),
+                "transferTo() != 0");
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testReadClosed() throws IOException {
+        closedReader.read();
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testReadBIIClosed() throws IOException {
+        closedReader.read(new char[1], 0, 1);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testReadCharBufferClosed() throws IOException {
+        CharBuffer charBuffer = CharBuffer.allocate(0);
+        closedReader.read(charBuffer);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testReadCharBufferZeroRemainingClosed() throws IOException {
+        CharBuffer charBuffer = CharBuffer.allocate(0);
+        closedReader.read(charBuffer);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testReadyClosed() throws IOException {
+        closedReader.ready();
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testSkipClosed() throws IOException {
+        closedReader.skip(1);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testTransferToClosed() throws IOException {
+        closedReader.transferTo(new StringWriter(7));
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/Reader/TransferTo.java b/ojluni/src/test/java/io/Reader/TransferTo.java
new file mode 100644
index 0000000..de1102d
--- /dev/null
+++ b/ojluni/src/test/java/io/Reader/TransferTo.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed source 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 source 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 Franklsource 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 test.java.io.Reader;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.Random;
+import org.testng.annotations.Test;
+
+import static java.lang.String.format;
+
+/*
+ * @test
+ * @bug 8191706
+ * @summary tests whether java.io.Reader.transferTo conforms to its
+ *          contract defined source the javadoc
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main TransferTo
+ * @key randomness
+ * @author Patrick Reinhart
+ */
+public class TransferTo {
+
+    private static Random generator = new Random();
+
+    @Test
+    public void ifOutIsNullThenNpeIsThrown() throws IOException {
+        try (Reader in = input()) {
+            assertThrowsNPE(() -> in.transferTo(null), "out");
+        }
+
+        try (Reader in = input((char) 1)) {
+            assertThrowsNPE(() -> in.transferTo(null), "out");
+        }
+
+        try (Reader in = input((char) 1, (char) 2)) {
+            assertThrowsNPE(() -> in.transferTo(null), "out");
+        }
+
+        Reader in = null;
+        try {
+            Reader fin = in = new ThrowingReader();
+            // null check should precede everything else:
+            // Reader shouldn't be touched if Writer is null
+            assertThrowsNPE(() -> fin.transferTo(null), "out");
+        } finally {
+            if (in != null)
+                try {
+                    in.close();
+                } catch (IOException ignored) { }
+        }
+    }
+
+    @Test
+    public void ifExceptionInInputNeitherStreamIsClosed()
+            throws IOException {
+        transferToThenCheckIfAnyClosed(input(0, new char[]{1, 2, 3}), output());
+        transferToThenCheckIfAnyClosed(input(1, new char[]{1, 2, 3}), output());
+        transferToThenCheckIfAnyClosed(input(2, new char[]{1, 2, 3}), output());
+    }
+
+    @Test
+    public void ifExceptionInOutputNeitherStreamIsClosed()
+            throws IOException {
+        transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(0));
+        transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(1));
+        transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(2));
+    }
+
+    private static void transferToThenCheckIfAnyClosed(Reader input,
+            Writer output)
+            throws IOException {
+        try (CloseLoggingReader in = new CloseLoggingReader(input);
+             CloseLoggingWriter out =
+                     new CloseLoggingWriter(output)) {
+            boolean thrown = false;
+            try {
+                in.transferTo(out);
+            } catch (IOException ignored) {
+                thrown = true;
+            }
+            if (!thrown)
+                throw new AssertionError();
+
+            if (in.wasClosed() || out.wasClosed()) {
+                throw new AssertionError();
+            }
+        }
+    }
+
+    @Test
+    public void onReturnNeitherStreamIsClosed()
+            throws IOException {
+        try (CloseLoggingReader in =
+                     new CloseLoggingReader(input(new char[]{1, 2, 3}));
+             CloseLoggingWriter out =
+                     new CloseLoggingWriter(output())) {
+
+            in.transferTo(out);
+
+            if (in.wasClosed() || out.wasClosed()) {
+                throw new AssertionError();
+            }
+        }
+    }
+
+    @Test
+    public void onReturnInputIsAtEnd() throws IOException {
+        try (Reader in = input(new char[]{1, 2, 3});
+             Writer out = output()) {
+
+            in.transferTo(out);
+
+            if (in.read() != -1) {
+                throw new AssertionError();
+            }
+        }
+    }
+
+    @Test
+    public void contents() throws IOException {
+        checkTransferredContents(new char[0]);
+        checkTransferredContents(createRandomChars(1024, 4096));
+        // to span through several batches
+        checkTransferredContents(createRandomChars(16384, 16384));
+    }
+
+    private static void checkTransferredContents(char[] chars)
+            throws IOException {
+        try (Reader in = input(chars);
+             StringWriter out = new StringWriter()) {
+            in.transferTo(out);
+
+            char[] outChars = out.toString().toCharArray();
+            if (!Arrays.equals(chars, outChars)) {
+                throw new AssertionError(
+                        format("chars.length=%s, outChars.length=%s",
+                                chars.length, outChars.length));
+            }
+        }
+    }
+
+    private static char[] createRandomChars(int min, int maxRandomAdditive) {
+        char[] chars = new char[min + generator.nextInt(maxRandomAdditive)];
+        for (int index=0; index<chars.length; index++) {
+            chars[index] = (char)generator.nextInt();
+        }
+        return chars;
+    }
+
+    private static Writer output() {
+        return output(-1);
+    }
+
+    private static Writer output(int exceptionPosition) {
+        return new Writer() {
+
+            int pos;
+
+            @Override
+            public void write(int b) throws IOException {
+                if (pos++ == exceptionPosition)
+                    throw new IOException();
+            }
+
+            @Override
+            public void write(char[] chars, int off, int len) throws IOException {
+                for (int i=0; i<len; i++) {
+                    write(chars[off + i]);
+                }
+            }
+
+            @Override
+            public Writer append(CharSequence csq, int start, int end) throws IOException {
+                for (int i = start; i < end; i++) {
+                    write(csq.charAt(i));
+                }
+                return this;
+            }
+
+            @Override
+            public void flush() throws IOException {
+            }
+
+            @Override
+            public void close() throws IOException {
+            }
+        };
+    }
+
+    private static Reader input(char... chars) {
+        return input(-1, chars);
+    }
+
+    private static Reader input(int exceptionPosition, char... chars) {
+        return new Reader() {
+
+            int pos;
+
+            @Override
+            public int read() throws IOException {
+                if (pos == exceptionPosition) {
+                    throw new IOException();
+                }
+
+                if (pos >= chars.length)
+                    return -1;
+                return chars[pos++];
+            }
+
+            @Override
+            public int read(char[] cbuf, int off, int len) throws IOException {
+                int c = read();
+                if (c == -1) {
+                    return -1;
+                }
+                cbuf[off] = (char)c;
+
+                int i = 1;
+                for (; i < len ; i++) {
+                    c = read();
+                    if (c == -1) {
+                        break;
+                    }
+                    cbuf[off + i] = (char)c;
+                }
+                return i;
+            }
+
+            @Override
+            public void close() throws IOException {
+            }
+        };
+    }
+
+    private static class ThrowingReader extends Reader {
+
+        boolean closed;
+
+        @Override
+        public int read(char[] b, int off, int len) throws IOException {
+            throw new IOException();
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closed) {
+                closed = true;
+                throw new IOException();
+            }
+        }
+        @Override
+        public int read() throws IOException {
+            throw new IOException();
+        }
+    }
+
+    private static class CloseLoggingReader extends FilterReader {
+
+        boolean closed;
+
+        CloseLoggingReader(Reader in) {
+            super(in);
+        }
+
+        @Override
+        public void close() throws IOException {
+            closed = true;
+            super.close();
+        }
+
+        boolean wasClosed() {
+            return closed;
+        }
+    }
+
+    private static class CloseLoggingWriter extends FilterWriter {
+
+        boolean closed;
+
+        CloseLoggingWriter(Writer out) {
+            super(out);
+        }
+
+        @Override
+        public void close() throws IOException {
+            closed = true;
+            super.close();
+        }
+
+        boolean wasClosed() {
+            return closed;
+        }
+    }
+
+    public interface Thrower {
+        public void run() throws Throwable;
+    }
+
+    public static void assertThrowsNPE(Thrower thrower, String message) {
+        assertThrows(thrower, NullPointerException.class, message);
+    }
+
+    public static <T extends Throwable> void assertThrows(Thrower thrower,
+            Class<T> throwable,
+            String message) {
+        Throwable thrown;
+        try {
+            thrower.run();
+            thrown = null;
+        } catch (Throwable caught) {
+            thrown = caught;
+        }
+
+        if (!throwable.isInstance(thrown)) {
+            String caught = thrown == null ?
+                    "nothing" : thrown.getClass().getCanonicalName();
+            throw new AssertionError(
+                    format("Expected to catch %s, but caught %s",
+                            throwable, caught), thrown);
+        }
+
+        if (thrown != null && !message.equals(thrown.getMessage())) {
+            throw new AssertionError(
+                    format("Expected exception message to be '%s', but it's '%s'",
+                            message, thrown.getMessage()));
+        }
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/Writer/NullWriter.java b/ojluni/src/test/java/io/Writer/NullWriter.java
new file mode 100644
index 0000000..e80b8a0
--- /dev/null
+++ b/ojluni/src/test/java/io/Writer/NullWriter.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @bug 8196298
+ * @run testng NullWriter
+ * @summary Check for expected behavior of Writer.nullWriter().
+ */
+public class NullWriter {
+    private static Writer openWriter;
+    private static Writer closedWriter;
+
+    @BeforeGroups(groups = "open")
+    public static void openStream() {
+        openWriter = Writer.nullWriter();
+    }
+
+    @BeforeGroups(groups = "closed")
+    public static void openAndCloseStream() throws IOException {
+        closedWriter = Writer.nullWriter();
+        closedWriter.close();
+    }
+
+    @AfterGroups(groups = "open")
+    public static void closeStream() throws IOException {
+        openWriter.close();
+    }
+
+    @Test(groups = "open")
+    public static void testOpen() {
+        assertNotNull(openWriter, "Writer.nullWriter() returned null");
+    }
+
+    @Test(groups = "open")
+    public static void testAppendChar() throws IOException {
+        assertSame(openWriter, openWriter.append('x'));
+    }
+
+    @Test(groups = "open")
+    public static void testAppendCharSequence() throws IOException {
+        CharSequence cs = "abc";
+        assertSame(openWriter, openWriter.append(cs));
+    }
+
+    @Test(groups = "open")
+    public static void testAppendCharSequenceNull() throws IOException {
+        assertSame(openWriter, openWriter.append(null));
+    }
+
+    @Test(groups = "open")
+    public static void testAppendCharSequenceII() throws IOException {
+        CharSequence cs = "abc";
+        assertSame(openWriter, openWriter.append(cs, 0, 1));
+    }
+
+    @Test(groups = "open")
+    public static void testAppendCharSequenceIINull() throws IOException {
+        assertSame(openWriter, openWriter.append(null, 2, 1));
+    }
+
+    @Test(groups = "open")
+    public static void testFlush() throws IOException {
+        openWriter.flush();
+    }
+
+    @Test(groups = "open")
+    public static void testWrite() throws IOException {
+        openWriter.write(62832);
+    }
+
+    @Test(groups = "open")
+    public static void testWriteString() throws IOException {
+        openWriter.write("");
+    }
+
+    @Test(groups = "open")
+    public static void testWriteStringII() throws IOException {
+        openWriter.write("", 0, 0);
+    }
+
+    @Test(groups = "open")
+    public static void testWriteBII() throws IOException, Exception {
+        openWriter.write(new char[]{(char) 6}, 0, 1);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testAppendCharClosed() throws IOException {
+        closedWriter.append('x');
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testAppendCharSequenceClosed() throws IOException {
+        CharSequence cs = "abc";
+        closedWriter.append(cs);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testAppendCharSequenceNullClosed() throws IOException {
+        closedWriter.append(null);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testAppendCharSequenceIIClosed() throws IOException {
+        CharSequence cs = "abc";
+        closedWriter.append(cs, 0, 1);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testAppendCharSequenceIINullClosed() throws IOException {
+        closedWriter.append(null, 2, 1);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testFlushClosed() throws IOException {
+        closedWriter.flush();
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testWriteClosed() throws IOException {
+        closedWriter.write(62832);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testWriteStringClosed() throws IOException {
+        closedWriter.write("");
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testWriteStringIIClosed() throws IOException {
+        closedWriter.write("", 0, 0);
+    }
+
+    @Test(groups = "closed", expectedExceptions = IOException.class)
+    public static void testWriteBIIClosed() throws IOException {
+        closedWriter.write(new char[]{(char) 6}, 0, 1);
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java b/ojluni/src/test/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java
new file mode 100644
index 0000000..fda5277
--- /dev/null
+++ b/ojluni/src/test/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// Android-added: package name
+package test.java.lang.invoke.VarHandles;
+
+/*
+ * @test
+ * @run testng VarHandleTestAccessModeMethodNames
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.stream.Stream;
+
+import static org.testng.Assert.assertEquals;
+
+public class VarHandleTestAccessModeMethodNames {
+
+    @DataProvider
+    public static Object[][] accessModesProvider() {
+        return Stream.of(VarHandle.AccessMode.values()).
+                map(am -> new Object[]{am}).
+                toArray(Object[][]::new);
+    }
+
+    @Test(dataProvider = "accessModesProvider")
+    public void testMethodName(VarHandle.AccessMode am) {
+        assertEquals(am.methodName(), toMethodName(am.name()));
+    }
+
+    private static String toMethodName(String name) {
+        StringBuilder s = new StringBuilder(name.toLowerCase());
+        int i;
+        while ((i = s.indexOf("_")) !=  -1) {
+            s.deleteCharAt(i);
+            s.setCharAt(i, Character.toUpperCase(s.charAt(i)));
+        }
+        return s.toString();
+    }
+
+    // BEGIN Android-removed: test for AccessMode return type (not present on Android).
+    // @Test(dataProvider = "accessModesProvider")
+    // public void testReturnType(VarHandle.AccessMode am) throws Exception {
+    //     assertEquals(getReturnType(am.methodName()), getAccessModeReturnType(am));
+    // }
+    //
+    // private static Class<?> getReturnType(String name) throws Exception {
+    //     return VarHandle.class.getMethod(name, Object[].class).getReturnType();
+    // }
+    //
+    // private static Class<?> getAccessModeReturnType(VarHandle.AccessMode am) throws Exception {
+    //     Field field_am_at = VarHandle.AccessMode.class.getDeclaredField("at");
+    //     field_am_at.setAccessible(true);
+    //     Field field_at_returnType = field_am_at.getType().getDeclaredField("returnType");
+    //     field_at_returnType.setAccessible(true);
+    //     return (Class<?>) field_at_returnType.get(field_am_at.get(am));
+    // }
+    // END Android-removed: test for AccessMode return type (not present on Android). */
+
+    // BEGIN Android-added: valueFromMethodName test (b/203822312)
+    @Test(dataProvider = "accessModesProvider")
+    public void testValueFromMethodName(VarHandle.AccessMode am) throws Exception {
+        VarHandle.AccessMode other = VarHandle.AccessMode.valueFromMethodName(am.methodName());
+        assertEquals(am, other);
+    }
+    // END Android-added: valueFromMethodName test (b/203822312)
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/AddTests.java b/ojluni/src/test/java/math/BigDecimal/AddTests.java
new file mode 100644
index 0000000..a7f13bd
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/AddTests.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6362557
+ * @summary Some tests of add(BigDecimal, mc)
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+import java.util.Set;
+import java.util.EnumSet;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class AddTests {
+
+    private static Set<RoundingMode> nonExactRoundingModes =
+        EnumSet.complementOf(EnumSet.of(RoundingMode.UNNECESSARY));
+
+    /**
+     * Test for some simple additions, particularly, it will test
+     * the overflow case.
+     */
+    private static int simpleTests() {
+        int failures = 0;
+
+        BigDecimal[] bd1 = {
+            new BigDecimal(new BigInteger("7812404666936930160"), 11),
+            new BigDecimal(new BigInteger("7812404666936930160"), 12),
+            new BigDecimal(new BigInteger("7812404666936930160"), 13),
+        };
+        BigDecimal bd2 = new BigDecimal(new BigInteger("2790000"), 1);
+        BigDecimal[] expectedResult = {
+            new BigDecimal("78403046.66936930160"),
+            new BigDecimal("8091404.666936930160"),
+            new BigDecimal("1060240.4666936930160"),
+        };
+        for (int i = 0; i < bd1.length; i++) {
+            if (!bd1[i].add(bd2).equals(expectedResult[i]))
+                failures++;
+        }
+        return failures;
+    }
+
+    /**
+     * Test for extreme value of scale and rounding precision that
+     * could cause integer overflow in right-shift-into-sticky-bit
+     * computations.
+     */
+    @Test
+    public void extremaTests() {
+        addWithoutException(valueOf(1, -Integer.MAX_VALUE),
+                                        valueOf(2, Integer.MAX_VALUE), null);
+        addWithoutException(valueOf(1, -Integer.MAX_VALUE),
+                                        valueOf(-2, Integer.MAX_VALUE), null);
+    }
+
+    /**
+     * Print sum of b1 and b2; correct result will not throw an
+     * exception.
+     */
+    private static void addWithoutException(BigDecimal b1, BigDecimal b2, MathContext mc) {
+        if (mc == null)
+            mc = new MathContext(2, RoundingMode.DOWN);
+
+        try {
+            BigDecimal sum = b1.add(b2, mc);
+        } catch(ArithmeticException ae) {
+            Assert.fail("Unexpected ArithmeticException: " + ae.getMessage());
+        }
+    }
+
+    /**
+     * Test combinations of operands that may meet the condensation
+     * criteria when rounded to different precisions.
+     */
+    @Test
+    public void roundingGradationTests() {
+        roundAway(new BigDecimal("1234e100"),
+                              new BigDecimal(   "1234e97"));
+
+        roundAway(new BigDecimal("1234e100"),
+                              new BigDecimal(    "1234e96"));
+
+        roundAway(new BigDecimal("1234e100"),
+                              new BigDecimal(     "1234e95"));
+
+        roundAway(new BigDecimal("1234e100"),
+                              new BigDecimal(      "1234e94"));
+
+        roundAway(new BigDecimal("1234e100"),
+                              new BigDecimal(       "1234e93"));
+
+        roundAway(new BigDecimal("1234e100"),
+                              new BigDecimal(        "1234e92"));
+
+        roundAway(new BigDecimal("1234e100"),
+                              new BigDecimal("1234e50"));
+
+
+        roundAway(new BigDecimal("1000e100"),
+                              new BigDecimal(   "1234e97"));
+
+        roundAway(new BigDecimal("1000e100"),
+                              new BigDecimal(    "1234e96"));
+
+        roundAway(new BigDecimal("1000e100"),
+                              new BigDecimal(     "1234e95"));
+
+        roundAway(new BigDecimal("1000e100"),
+                              new BigDecimal(      "1234e94"));
+
+        roundAway(new BigDecimal("1000e100"),
+                              new BigDecimal(       "1234e93"));
+
+        roundAway(new BigDecimal("1000e100"),
+                              new BigDecimal(        "1234e92"));
+
+        roundAway(new BigDecimal("1000e100"),
+                              new BigDecimal("1234e50"));
+
+
+
+        roundAway(new BigDecimal("1999e100"),
+                              new BigDecimal(   "1234e97"));
+
+        roundAway(new BigDecimal("1999e100"),
+                              new BigDecimal(    "1234e96"));
+
+        roundAway(new BigDecimal("1999e100"),
+                              new BigDecimal(     "1234e95"));
+
+        roundAway(new BigDecimal("1999e100"),
+                              new BigDecimal(      "1234e94"));
+
+        roundAway(new BigDecimal("1999e100"),
+                              new BigDecimal(       "1234e93"));
+
+        roundAway(new BigDecimal("1999e100"),
+                              new BigDecimal(        "1234e92"));
+
+        roundAway(new BigDecimal("1999e100"),
+                              new BigDecimal("1234e50"));
+
+
+
+        roundAway(new BigDecimal("9999e100"),
+                              new BigDecimal(   "1234e97"));
+
+        roundAway(new BigDecimal("9999e100"),
+                              new BigDecimal(    "1234e96"));
+
+        roundAway(new BigDecimal("9999e100"),
+                              new BigDecimal(     "1234e95"));
+
+        roundAway(new BigDecimal("9999e100"),
+                              new BigDecimal(      "1234e94"));
+
+        roundAway(new BigDecimal("9999e100"),
+                              new BigDecimal(       "1234e93"));
+
+        roundAway(new BigDecimal("9999e100"),
+                              new BigDecimal(        "1234e92"));
+
+        roundAway(new BigDecimal("9999e100"),
+                              new BigDecimal("1234e50"));
+    }
+
+    private static void roundAway(BigDecimal b1, BigDecimal b2) {
+        b1.precision();
+        b2.precision();
+
+        BigDecimal b1_negate = b1.negate();
+        BigDecimal b2_negate = b2.negate();
+
+        b1_negate.precision();
+        b2_negate.precision();
+
+        roundAway1(b1,        b2);
+        roundAway1(b1,        b2_negate);
+        roundAway1(b1_negate, b2);
+        roundAway1(b1_negate, b2_negate);
+    }
+
+    private static void roundAway1(BigDecimal b1, BigDecimal b2) {
+        roundAway0(b1, b2);
+        roundAway0(b2, b1);
+    }
+
+    /**
+     * Compare b1.add(b2, mc) with b1.add(b2).round(mc) for a variety
+     * of MathContexts.
+     */
+    private static void roundAway0(BigDecimal b1, BigDecimal b2) {
+        BigDecimal exactSum = b1.add(b2);
+
+        for(int precision = 1 ; precision < exactSum.precision()+2; precision++) {
+            for(RoundingMode rm : nonExactRoundingModes) {
+                MathContext mc = new MathContext(precision, rm);
+                BigDecimal roundedExactSum = exactSum.round(mc);
+
+                try {
+                    BigDecimal sum = b1.add(b2, mc);
+
+                    Assert.assertEquals(sum, roundedExactSum, "Exact sum " + exactSum +
+                                           "\trounded by " + mc +
+                                           "\texpected: " + roundedExactSum + " got: ");
+                } catch (ArithmeticException ae) {
+                    Assert.fail("Unexpected ArithmeticException: " + ae.getMessage());
+                }
+            }
+        }
+    }
+
+    /**
+     * Verify calling the precision method should not change the
+     * computed result.
+     */
+    @Test
+    public void precisionConsistencyTest() {
+        MathContext mc = new MathContext(1,RoundingMode.DOWN);
+        BigDecimal a = BigDecimal.valueOf(1999, -1); //value is equivalent to 19990
+
+        BigDecimal sum1 = a.add(BigDecimal.ONE, mc);
+        a.precision();
+        BigDecimal sum2 = a.add(BigDecimal.ONE, mc);
+
+        Assert.assertEquals(sum2, sum1, "Unequal sums after calling precision!" +
+            "Before:\t" + sum1.toString() +
+            "After:\t" + sum2.toString());
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/CompareToTests.java b/ojluni/src/test/java/math/BigDecimal/CompareToTests.java
new file mode 100644
index 0000000..4885944
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/CompareToTests.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2006, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6473768
+ * @summary Tests of BigDecimal.compareTo
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class CompareToTests {
+
+    @Test
+    public void compareToTests() {
+        final BigDecimal MINUS_ONE = BigDecimal.ONE.negate();
+
+        // First operand, second operand, expected compareTo result
+        BigDecimal [][] testCases = {
+            // Basics
+            {valueOf(0),        valueOf(0),     ZERO},
+            {valueOf(0),        valueOf(1),     MINUS_ONE},
+            {valueOf(1),        valueOf(2),     MINUS_ONE},
+            {valueOf(2),        valueOf(1),     ONE},
+            {valueOf(10),       valueOf(10),    ZERO},
+
+            // Significands would compare differently than scaled value
+            {valueOf(2,1),      valueOf(2),     MINUS_ONE},
+            {valueOf(2,-1),     valueOf(2),     ONE},
+            {valueOf(1,1),      valueOf(2),     MINUS_ONE},
+            {valueOf(1,-1),     valueOf(2),     ONE},
+            {valueOf(5,-1),     valueOf(2),     ONE},
+
+            // Boundary and near boundary values
+            {valueOf(Long.MAX_VALUE),            valueOf(Long.MAX_VALUE), ZERO},
+            {valueOf(Long.MAX_VALUE).negate(),   valueOf(Long.MAX_VALUE), MINUS_ONE},
+
+            {valueOf(Long.MAX_VALUE-1),          valueOf(Long.MAX_VALUE), MINUS_ONE},
+            {valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MAX_VALUE), MINUS_ONE},
+
+            {valueOf(Long.MIN_VALUE),            valueOf(Long.MAX_VALUE), MINUS_ONE},
+            {valueOf(Long.MIN_VALUE).negate(),   valueOf(Long.MAX_VALUE), ONE},
+
+            {valueOf(Long.MIN_VALUE+1),          valueOf(Long.MAX_VALUE), MINUS_ONE},
+            {valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MAX_VALUE), ZERO},
+
+            {valueOf(Long.MAX_VALUE),            valueOf(Long.MIN_VALUE), ONE},
+            {valueOf(Long.MAX_VALUE).negate(),   valueOf(Long.MIN_VALUE), ONE},
+
+            {valueOf(Long.MAX_VALUE-1),          valueOf(Long.MIN_VALUE), ONE},
+            {valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MIN_VALUE), ONE},
+
+            {valueOf(Long.MIN_VALUE),            valueOf(Long.MIN_VALUE), ZERO},
+            {valueOf(Long.MIN_VALUE).negate(),   valueOf(Long.MIN_VALUE), ONE},
+
+            {valueOf(Long.MIN_VALUE+1),          valueOf(Long.MIN_VALUE), ONE},
+            {valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MIN_VALUE), ONE},
+        };
+
+        for (BigDecimal[] testCase : testCases) {
+            BigDecimal a = testCase[0];
+            BigDecimal a_negate = a.negate();
+            BigDecimal b = testCase[1];
+            BigDecimal b_negate = b.negate();
+            int expected = testCase[2].intValue();
+
+            compareToTest(a,        b,         expected);
+            compareToTest(a_negate, b_negate, -expected);
+        }
+    }
+
+    private static void compareToTest(BigDecimal a, BigDecimal b, int expected) {
+        int result = a.compareTo(b);
+        Assert.assertEquals(result, expected, "(" + a + ").compareTo(" + b + ") => " + result +
+                               "\n\tExpected " + expected);
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/Constructor.java b/ojluni/src/test/java/math/BigDecimal/Constructor.java
new file mode 100644
index 0000000..25ad7bc
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/Constructor.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1999, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4259453
+ * @summary Test string constructor of BigDecimal
+ */
+import java.math.BigDecimal;
+
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class Constructor {
+
+    @Test(expectedExceptions = NumberFormatException.class)
+    public void testConstructor() throws Exception {
+        BigDecimal bd = new BigDecimal("1.2e");
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/DivideMcTests.java b/ojluni/src/test/java/math/BigDecimal/DivideMcTests.java
new file mode 100644
index 0000000..acf717f
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/DivideMcTests.java
@@ -0,0 +1,5783 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 7036582
+ * @summary Some tests for the divide(..,MathContext) method.
+ * @run main DivideMcTests
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 DivideMcTests
+ * @author Sergey V. Kuksenko
+ */
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class DivideMcTests {
+
+    static String[] value = new String[75];
+    static String[][] results = new String[75][75];
+    static {
+        value[0]="11061";
+        value[1]="5030285645";
+        value[2]="224198292018431";
+        value[3]="19226185404220649458";
+        value[4]="2754593222460641763294400";
+        value[5]="88290e4";
+        value[6]="14207e-4";
+        value[7]="9206524943e4";
+        value[8]="9637167289e-4";
+        value[9]="987673128759528e4";
+        value[10]="270627774630281e-4";
+        value[11]="81503625886547904651e4";
+        value[12]="60700032235397315737e-4";
+        value[13]="6477954854329556663533122e4";
+        value[14]="8056417378028557868905113e-4";
+        value[15]="74996e8";
+        value[16]="65282e-8";
+        value[17]="6336626690e8";
+        value[18]="8318166778e-8";
+        value[19]="983114227763768e8";
+        value[20]="245802997834566e-8";
+        value[21]="52727924122290902686e8";
+        value[22]="42785567085625398961e-8";
+        value[23]="4810906998143118279742863e8";
+        value[24]="8077506080975981172874361e-8";
+        value[25]="80689e12";
+        value[26]="30125e-12";
+        value[27]="6921467144e12";
+        value[28]="1953347181e-12";
+        value[29]="405471649883944e12";
+        value[30]="866720590936024e-12";
+        value[31]="33231666378140173438e12";
+        value[32]="42631490906110209257e-12";
+        value[33]="7723154992826793726050991e12";
+        value[34]="1611437259018380210686834e-12";
+        value[35]="65645e16";
+        value[36]="31153e-16";
+        value[37]="7758733150e16";
+        value[38]="6365465077e-16";
+        value[39]="727973863299662e16";
+        value[40]="351084160935215e-16";
+        value[41]="45470432070181568402e16";
+        value[42]="97216256670931719037e-16";
+        value[43]="2520581904836081418366563e16";
+        value[44]="3700768934485477578987416e-16";
+        value[45]="28736e20";
+        value[46]="52779e-20";
+        value[47]="7904805864e20";
+        value[48]="6373815349e-20";
+        value[49]="186651310031326e20";
+        value[50]="189125880591366e-20";
+        value[51]="74987916068454915171e20";
+        value[52]="10554589082317914511e-20";
+        value[53]="3599986721169840668392202e20";
+        value[54]="2588106172836128849130551e-20";
+        value[55]="71080e24";
+        value[56]="61576e-24";
+        value[57]="7086656363e24";
+        value[58]="7703864845e-24";
+        value[59]="361167296280301e24";
+        value[60]="149150690375117e-24";
+        value[61]="78129219923655854302e24";
+        value[62]="20861932490694515212e-24";
+        value[63]="9185868654811652011998047e24";
+        value[64]="1996563690880014012200226e-24";
+        value[65]="84665e28";
+        value[66]="94968e-28";
+        value[67]="2622821029e28";
+        value[68]="4451579486e-28";
+        value[69]="590522407411869e28";
+        value[70]="606293232614518e-28";
+        value[71]="96628087822208148505e28";
+        value[72]="24875240094942654314e-28";
+        value[73]="5099400093819597146233149e28";
+        value[74]="8906650752845770170008864e-28";
+        //--------------------------------------------
+        initResults1();
+        initResults2();
+    }
+
+    private static void initResults1() {
+        results[0][0]="1";
+        results[0][1]="0.000002198881093560642";
+        results[0][2]="4.933579065397471E-11";
+        results[0][3]="5.753091300977375E-16";
+        results[0][4]="4.015474920147867E-21";
+        results[0][5]="0.00001252803261977574";
+        results[0][6]="7785.598648553530";
+        results[0][7]="1.201430514605841E-10";
+        results[0][8]="0.01147743903192921";
+        results[0][9]="1.119904923797219E-15";
+        results[0][10]="4.087163638363069E-7";
+        results[0][11]="1.357117536758031E-20";
+        results[0][12]="1.822239559462666E-12";
+        results[0][13]="1.707483341383177E-25";
+        results[0][14]="1.372942771084022E-17";
+        results[0][15]="1.474878660195210E-9";
+        results[0][16]="16943414.72381361";
+        results[0][17]="1.745565983468090E-14";
+        results[0][18]="132.9740109233477";
+        results[0][19]="1.125098151123273E-19";
+        results[0][20]="0.004499945117611804";
+        results[0][21]="2.097749946374985E-24";
+        results[0][22]="2.585217575324869E-8";
+        results[0][23]="2.299150660004288E-29";
+        results[0][24]="1.369358300583728E-13";
+        results[0][25]="1.370818822887878E-13";
+        results[0][26]="367170124481.3278";
+        results[0][27]="1.598071589430057E-18";
+        results[0][28]="5662587.842852089";
+        results[0][29]="2.727934247231818E-23";
+        results[0][30]="12.76189825841631";
+        results[0][31]="3.328451806821200E-28";
+        results[0][32]="0.0002594560913752765";
+        results[0][33]="1.432186717769276E-33";
+        results[0][34]="6.864058738928437E-9";
+        results[0][35]="1.684972198948892E-17";
+        results[0][36]="3550540878888069";
+        results[0][37]="1.425619335806130E-22";
+        results[0][38]="17376577934.52694";
+        results[0][39]="1.519422682273810E-27";
+        results[0][40]="315052.6634564146";
+        results[0][41]="2.432569803367569E-32";
+        results[0][42]="1.137772670824026";
+        results[0][43]="4.388272398043467E-37";
+        results[0][44]="0.00002988838318687904";
+        results[0][45]="3.849178730512249E-21";
+        results[0][46]="2.095719888592054E+19";
+        results[0][47]="1.399275351008165E-26";
+        results[0][48]="173538130528606.9";
+        results[0][49]="5.926023234524105E-31";
+        results[0][50]="5848485656.967753";
+        results[0][51]="1.475037656720937E-36";
+        results[0][52]="104798.0164242535";
+        results[0][53]="3.072511333154488E-41";
+        results[0][54]="0.4273781391232109";
+        results[0][55]="1.556133933595948E-25";
+        results[0][56]="1.796316746784461E+23";
+        results[0][57]="1.560820707738894E-30";
+        results[0][58]="1.435772852009322E+18";
+        results[0][59]="3.062569649555309E-35";
+        results[0][60]="74159898101586.80";
+        results[0][61]="1.415731529229177E-40";
+        results[0][62]="530200162.6615257";
+        results[0][63]="1.204132174718842E-45";
+        results[0][64]="5540.018608234184";
+        results[0][65]="1.306443040217327E-29";
+        results[0][66]="1.164708112206217E+27";
+        results[0][67]="4.217214929154817E-34";
+        results[0][68]="2.484736043641657E+22";
+        results[0][69]="1.873087263272185E-39";
+        results[0][70]="1.824364747121068E+17";
+        results[0][71]="1.144698218633054E-44";
+        results[0][72]="4446590247082.196";
+        results[0][73]="2.169078675235893E-49";
+        results[0][74]="12418809.61422664";
+        results[1][0]="454776.7511979025";
+        results[1][1]="1";
+        results[1][2]="0.00002243677059139446";
+        results[1][3]="2.616372171203405E-10";
+        results[1][4]="1.826144638701504E-15";
+        results[1][5]="5.697457973722958";
+        results[1][6]="3540709259.519955";
+        results[1][7]="0.00005463826662224685";
+        results[1][8]="5219.672435012765";
+        results[1][9]="5.093067228950338E-10";
+        results[1][10]="0.1858747001068956";
+        results[1][11]="6.171855043605175E-15";
+        results[1][12]="8.287121867567282E-7";
+        results[1][13]="7.765237267187802E-20";
+        results[1][14]="6.243824530142372E-12";
+        results[1][15]="0.0006707405254946931";
+        results[1][16]="7705471102294.660";
+        results[1][17]="7.938428269631898E-9";
+        results[1][18]="60473488.68147447";
+        results[1][19]="5.116684819466090E-14";
+        results[1][20]="2046.470421156359";
+        results[1][21]="9.540079054379898E-19";
+        results[1][22]="0.01175696850045963";
+        results[1][23]="1.045600267671264E-23";
+        results[1][24]="6.227523191653488E-8";
+        results[1][25]="6.234165307538822E-8";
+        results[1][26]="1.669804363485477E+17";
+        results[1][27]="7.267658056226699E-13";
+        results[1][28]="2575213302545.012";
+        results[1][29]="1.240601074437582E-17";
+        results[1][30]="5803814.629080740";
+        results[1][31]="1.513702499224934E-22";
+        results[1][32]="117.9945983141544";
+        results[1][33]="6.513252226158986E-28";
+        results[1][34]="0.003121614333321446";
+        results[1][35]="7.662861824967629E-12";
+        results[1][36]="1.614703445896061E+21";
+        results[1][37]="6.483385299828233E-17";
+        results[1][38]="7902463660001319";
+        results[1][39]="6.909981111408860E-22";
+        results[1][40]="143278626742.9544";
+        results[1][41]="1.106276192237624E-26";
+        results[1][42]="517432.5588391111";
+        results[1][43]="1.995684264553637E-31";
+        results[1][44]="13.59254180428686";
+        results[1][45]="1.750516997842428E-15";
+        results[1][46]="9.530846823547244E+24";
+        results[1][47]="6.363578981627979E-21";
+        results[1][48]="7.892110721075739E+19";
+        results[1][49]="2.695017594120158E-25";
+        results[1][50]="2659755306503325";
+        results[1][51]="6.708128334181145E-31";
+        results[1][52]="47659701441.40646";
+        results[1][53]="1.397306722110734E-35";
+        results[1][54]="194361.6416434591";
+        results[1][55]="7.076935347495779E-20";
+        results[1][56]="8.169230942250227E+28";
+        results[1][57]="7.098249706679054E-25";
+        results[1][58]="6.529561130949462E+23";
+        results[1][59]="1.392785475542062E-29";
+        results[1][60]="3.372619752780715E+19";
+        results[1][61]="6.438417854312836E-35";
+        results[1][62]="241122707459808.1";
+        results[1][63]="5.476113184315002E-40";
+        results[1][64]="2519471664.228668";
+        results[1][65]="5.941399214551468E-24";
+        results[1][66]="5.296821713629854E+32";
+        results[1][67]="1.917891304584321E-28";
+        results[1][68]="1.130000185511682E+28";
+        results[1][69]="8.518365403010947E-34";
+        results[1][70]="8.296786726957023E+22";
+        results[1][71]="5.205821369719668E-39";
+        results[1][72]="2.022205866476320E+18";
+        results[1][73]="9.864465530164297E-44";
+        results[1][74]="5647785890103.269";
+        results[2][0]="20269260647.17756";
+        results[2][1]="44569.69401753148";
+        results[2][2]="1";
+        results[2][3]="0.00001166109071065203";
+        results[2][4]="8.139070777868161E-11";
+        results[2][5]="253933.9585665772";
+        results[2][6]="157808328301844.9";
+        results[2][7]="2.435210825001846";
+        results[2][8]="232639203.3002624";
+        results[2][9]="0.00002269964480050335";
+        results[2][10]="8284.378509364762";
+        results[2][11]="2.750776908140411E-10";
+        results[2][12]="0.03693544859234678";
+        results[2][13]="3.460942489720927E-15";
+        results[2][14]="2.782853488076028E-7";
+        results[2][15]="29.89469998645674";
+        results[2][16]="3.434304892902040E+17";
+        results[2][17]="0.0003538133189576156";
+        results[2][18]="2695284886705.971";
+        results[2][19]="2.280490767877520E-9";
+        results[2][20]="91210560.48686773";
+        results[2][21]="4.251984043567731E-14";
+        results[2][22]="524.0044886392415";
+        results[2][23]="4.660208399475724E-19";
+        results[2][24]="0.002775588031390770";
+        results[2][25]="0.002778548402117154";
+        results[2][26]="7.442266954968664E+21";
+        results[2][27]="3.239172957900716E-8";
+        results[2][28]="1.147764689243079E+17";
+        results[2][29]="5.529321028550383E-13";
+        results[2][30]="258674242152.6016";
+        results[2][31]="6.746525722402801E-18";
+        results[2][32]="5258983.142583397";
+        results[2][33]="2.902936587789118E-23";
+        results[2][34]="139.1293956768774";
+        results[2][35]="3.415314068374301E-7";
+        results[2][36]="7.196683851264116E+25";
+        results[2][37]="2.889624990111060E-12";
+        results[2][38]="3.522103873109208E+20";
+        results[2][39]="3.079757438024150E-17";
+        results[2][40]="6385884553185581";
+        results[2][41]="4.930639138691073E-22";
+        results[2][42]="23061810822.16754";
+        results[2][43]="8.894703702675794E-27";
+        results[2][44]="605815.4291375707";
+        results[2][45]="7.802000696632482E-11";
+        results[2][46]="4.247869266534626E+29";
+        results[2][47]="2.836227680675536E-16";
+        results[2][48]="3.517489599908254E+24";
+        results[2][49]="1.201161095417993E-20";
+        results[2][50]="1.185444801723589E+20";
+        results[2][51]="2.989792272847868E-26";
+        results[2][52]="2124178310210390";
+        results[2][53]="6.227753305311532E-31";
+        results[2][54]="8662638896.794075";
+        results[2][55]="3.154168430197397E-15";
+        results[2][56]="3.641001234546430E+33";
+        results[2][57]="3.163668174867180E-20";
+        results[2][58]="2.910205416751843E+28";
+        results[2][59]="6.207602247697180E-25";
+        results[2][60]="1.503166304189191E+24";
+        results[2][61]="2.869583137237347E-30";
+        results[2][62]="1.074676529216240E+19";
+        results[2][63]="2.440686890302896E-35";
+        results[2][64]="112292081160512.5";
+        results[2][65]="2.648063450285608E-19";
+        results[2][66]="2.360777230418994E+37";
+        results[2][67]="8.547982860420744E-24";
+        results[2][68]="5.036376250800950E+32";
+        results[2][69]="3.796609395417242E-29";
+        results[2][70]="3.697852457491911E+27";
+        results[2][71]="2.320218655583322E-34";
+        results[2][72]="9.012909670930670E+22";
+        results[2][73]="4.396562103259092E-39";
+        results[2][74]="2.517200889984344E+17";
+        results[3][0]="1738195950114877";
+        results[3][1]="3822086211.611279";
+        results[3][2]="85755.27151045421";
+        results[3][3]="1";
+        results[3][4]="0.000006979682243988879";
+        results[3][5]="21776175562.60126";
+        results[3][6]="1.353289604013560E+19";
+        results[3][7]="208832.1654832305";
+        results[3][8]="19950038042989.76";
+        results[3][9]="1.946614203058035";
+        results[3][10]="710429128.3659471";
+        results[3][11]="0.00002358936206222687";
+        results[3][12]="3167.409422397122";
+        results[3][13]="2.967940628880855E-10";
+        results[3][14]="0.02386443564437743";
+        results[3][15]="2563628.114062170";
+        results[3][16]="2.945097485404958E+22";
+        results[3][17]="30.34135723122526";
+        results[3][18]="2.311348872574943E+17";
+        results[3][19]="0.0001955641049764209";
+        results[3][20]="7821786379172.049";
+        results[3][21]="3.646300461142698E-9";
+        results[3][22]="44936147.19595487";
+        results[3][23]="3.996374365923399E-14";
+        results[3][24]="238.0213052330826";
+        results[3][25]="238.2751726284952";
+        results[3][26]="6.382136233766191E+26";
+        results[3][27]="0.002777761564740970";
+        results[3][28]="9.842687255615237E+21";
+        results[3][29]="4.741684260718020E-8";
+        results[3][30]="2.218267986855733E+16";
+        results[3][31]="5.785501450769154E-13";
+        results[3][32]="450985527261.1410";
+        results[3][33]="2.489421152634873E-18";
+        results[3][34]="11931079.10135604";
+        results[3][35]="0.02928811852269122";
+        results[3][36]="6.171535776400555E+30";
+        results[3][37]="2.478005755903675E-7";
+        results[3][38]="3.020389739265025E+25";
+        results[3][39]="2.641054352841019E-12";
+        results[3][40]="5.476232636928451E+20";
+        results[3][41]="4.228282980585251E-17";
+        results[3][42]="1977671848577708";
+        results[3][43]="7.627677310280051E-22";
+        results[3][44]="51951866610.91471";
+        results[3][45]="0.000006690626880644714";
+        results[3][46]="3.642771822925908E+34";
+        results[3][47]="2.432214748217965E-11";
+        results[3][48]="3.016432756753313E+29";
+        results[3][49]="1.030058958653646E-15";
+        results[3][50]="1.016581408324629E+25";
+        results[3][51]="2.563904481179269E-21";
+        results[3][52]="1.821594877287098E+20";
+        results[3][53]="5.340626755971191E-26";
+        results[3][54]="742866950591597.5";
+        results[3][55]="2.704865701212809E-10";
+        results[3][56]="3.122350494384281E+38";
+        results[3][57]="2.713012233047182E-15";
+        results[3][58]="2.495654556647489E+33";
+        results[3][59]="5.323346161801775E-20";
+        results[3][60]="1.289044345411101E+29";
+        results[3][61]="2.460818810556097E-25";
+        results[3][62]="9.215917754885128E+23";
+        results[3][63]="2.093017669499310E-30";
+        results[3][64]="9.629637908393713E+18";
+        results[3][65]="2.270854001561525E-14";
+        results[3][66]="2.024490923702789E+42";
+        results[3][67]="7.330345910620899E-19";
+        results[3][68]="4.318958128162389E+37";
+        results[3][69]="3.255792695231470E-24";
+        results[3][70]="3.171103414978191E+32";
+        results[3][71]="1.989709807731689E-29";
+        results[3][72]="7.729045159298581E+27";
+        results[3][73]="3.770283768775571E-34";
+        results[3][74]="2.158632457669644E+22";
+        results[4][0]="2.490365448386802E+20";
+        results[4][1]="547601750051441.0";
+        results[4][2]="12286414841.35031";
+        results[4][3]="143272.9979736873";
+        results[4][4]="1";
+        results[4][5]="3119937957255229";
+        results[4][6]="1.938898586936469E+24";
+        results[4][7]="29920010422.11961";
+        results[4][8]="2.858301760108257E+18";
+        results[4][9]="278897.2527702849";
+        results[4][10]="101785311068822.8";
+        results[4][11]="3.379718622942007";
+        results[4][12]="453804243.7569410";
+        results[4][13]="0.00004252257517076709";
+        results[4][14]="3419.129239720079";
+        results[4][15]="367298685591.3171";
+        results[4][16]="4.219529460587362E+27";
+        results[4][17]="4347097.213108260";
+        results[4][18]="3.311538823369143E+22";
+        results[4][19]="28.01905561601273";
+        results[4][20]="1.120650784053732E+18";
+        results[4][21]="0.0005224163985807529";
+        results[4][22]="6438136526151.358";
+        results[4][23]="5.725725364310391E-9";
+        results[4][24]="34102025.98235386";
+        results[4][25]="34138398.32518239";
+        results[4][26]="9.143877916881798E+31";
+        results[4][27]="397.9782270365194";
+        results[4][28]="1.410191311229400E+27";
+        results[4][29]="0.006793553194777180";
+        results[4][30]="3.178179047858768E+21";
+        results[4][31]="8.289061376328140E-8";
+        results[4][32]="6.461404853344776E+16";
+        results[4][33]="3.566668317571105E-13";
+        results[4][34]="1709401471912.486";
+        results[4][35]="4196.196545754653";
+        results[4][36]="8.842144327867755E+35";
+        results[4][37]="0.03550313136443727";
+        results[4][38]="4.327402929934638E+30";
+        results[4][39]="3.783917749429893E-7";
+        results[4][40]="7.845962674940902E+25";
+        results[4][41]="6.057987789095672E-12";
+        results[4][42]="2.833469747538924E+20";
+        results[4][43]="1.092840195819694E-16";
+        results[4][44]="7443299679674857";
+        results[4][45]="0.9585861715133080";
+        results[4][46]="5.219108400046689E+39";
+        results[4][47]="0.000003484706986930048";
+        results[4][48]="4.321733642460815E+34";
+        results[4][49]="1.475796350959623E-10";
+        results[4][50]="1.456486660549828E+30";
+        results[4][51]="3.673382815367253E-16";
+        results[4][52]="2.609853591624336E+25";
+        results[4][53]="7.651676063864807E-21";
+        results[4][54]="1.064327751068292E+20";
+        results[4][55]="0.00003875342181289592";
+        results[4][56]="4.473485160550607E+43";
+        results[4][57]="3.887013961679578E-10";
+        results[4][58]="3.575599102375792E+38";
+        results[4][59]="7.626917638530619E-15";
+        results[4][60]="1.846852478880778E+34";
+        results[4][61]="3.525688884584153E-20";
+        results[4][62]="1.320392165821326E+29";
+        results[4][63]="2.998729163210665E-25";
+        results[4][64]="1.379667092536635E+24";
+        results[4][65]="3.253520607642641E-9";
+        results[4][66]="2.900548840094181E+47";
+        results[4][67]="1.050240634798815E-13";
+        results[4][68]="6.187900791446503E+42";
+        results[4][69]="4.664671802266443E-19";
+        results[4][70]="4.543334931485233E+37";
+        results[4][71]="2.850716892513680E-24";
+        results[4][72]="1.107363471446723E+33";
+        results[4][73]="5.401798587640085E-29";
+        results[4][74]="3.092737437336386E+27";
+        results[5][0]="79820.99267697315";
+        results[5][1]="0.1755168716666387";
+        results[5][2]="0.000003938031784503595";
+        results[5][3]="4.592174586052730E-11";
+        results[5][4]="3.205191941956922E-16";
+        results[5][5]="1";
+        results[5][6]="621454212.7120434";
+        results[5][7]="0.000009589937630824491";
+        results[5][8]="916.1405769180272";
+        results[5][9]="8.939192272132398E-11";
+        results[5][10]="0.03262414588473695";
+        results[5][11]="1.083264689633546E-15";
+        results[5][12]="1.454529705315602E-7";
+        results[5][13]="1.362930152886002E-20";
+        results[5][14]="1.095896548766010E-12";
+        results[5][15]="0.0001177262787348659";
+        results[5][16]="1352440182592.445";
+        results[5][17]="1.393328095835799E-9";
+        results[5][18]="10614117.55214028";
+        results[5][19]="8.980645128168683E-15";
+        results[5][20]="359.1900862796728";
+        results[5][21]="1.674444831077185E-19";
+        results[5][22]="0.002063546331483886";
+        results[5][23]="1.835204879954603E-24";
+        results[5][24]="1.093035388830462E-8";
+        results[5][25]="1.094201192231903E-8";
+        results[5][26]="2.930788381742739E+16";
+        results[5][27]="1.275596606371755E-13";
+        results[5][28]="451993382737.0138";
+        results[5][29]="2.177464195715552E-18";
+        results[5][30]="1018667.387429325";
+        results[5][31]="2.656803272979331E-23";
+        results[5][32]="20.71004276966202";
+        results[5][33]="1.143185655111196E-28";
+        results[5][34]="0.0005478959823343203";
+        results[5][35]="1.344961535532028E-12";
+        results[5][36]="2.834076974930183E+20";
+        results[5][37]="1.137943505635324E-17";
+        results[5][38]="1387015700062728";
+        results[5][39]="1.212818267950047E-22";
+        results[5][40]="25147816342.61536";
+        results[5][41]="1.941701364608288E-27";
+        results[5][42]="90818.14402590475";
+        results[5][43]="3.502762589487909E-32";
+        results[5][44]="2.385720415486439";
+        results[5][45]="3.072452672605791E-16";
+        results[5][46]="1.672824418802933E+24";
+        results[5][47]="1.116915475458918E-21";
+        results[5][48]="1.385198584609954E+19";
+        results[5][49]="4.730210572065213E-26";
+        results[5][50]="466831930796205.5";
+        results[5][51]="1.177389699953815E-31";
+        results[5][52]="8365081701.561654";
+        results[5][53]="2.452509046236414E-36";
+        results[5][54]="34113.74731325223";
+        results[5][55]="1.242121553179516E-20";
+        results[5][56]="1.433837858906067E+28";
+        results[5][57]="1.245862582824943E-25";
+        results[5][58]="1.146048143060329E+23";
+        results[5][59]="2.444573495698746E-30";
+        results[5][60]="5.919516683291835E+18";
+        results[5][61]="1.130050960271621E-35";
+        results[5][62]="42321103301135.62";
+        results[5][63]="9.611502550034045E-41";
+        results[5][64]="442209784.7581557";
+        results[5][65]="1.042815803460698E-24";
+        results[5][66]="9.296815769522365E+31";
+        results[5][67]="3.366222819772885E-29";
+        results[5][68]="1.983340975437319E+27";
+        results[5][69]="1.495116847249808E-34";
+        results[5][70]="1.456226051200787E+22";
+        results[5][71]="9.137094812685324E-40";
+        results[5][72]="3.549312475498482E+17";
+        results[5][73]="1.731380130517828E-44";
+        results[5][74]="991281711273.9084";
+        results[6][0]="0.0001284422746587108";
+        results[6][1]="2.824292893609623E-10";
+        results[6][2]="6.336801173682476E-15";
+        results[6][3]="7.389401330167758E-20";
+        results[6][4]="5.157567325787970E-25";
+        results[6][5]="1.609129006682524E-9";
+        results[6][6]="1";
+        results[6][7]="1.543144681403597E-14";
+        results[6][8]="0.000001474188376517659";
+        results[6][9]="1.438431358140050E-19";
+        results[6][10]="5.249645946137250E-11";
+        results[6][11]="1.743112634004281E-24";
+        results[6][12]="2.340525939904718E-16";
+        results[6][13]="2.193130443091112E-29";
+        results[6][14]="1.763438924942655E-21";
+        results[6][15]="1.894367699610646E-13";
+        results[6][16]="2176.250727612512";
+        results[6][17]="2.242044654835111E-18";
+        results[6][18]="0.01707948443348703";
+        results[6][19]="1.445101657445832E-23";
+        results[6][20]="5.779831867454199E-7";
+        results[6][21]="2.694397747775916E-28";
+        results[6][22]="3.320512258624031E-12";
+        results[6][23]="2.953081405540270E-33";
+        results[6][24]="1.758834949497607E-17";
+        results[6][25]="1.760710877566955E-17";
+        results[6][26]="47160165.97510373";
+        results[6][27]="2.052599500138579E-22";
+        results[6][28]="727.3156629906847";
+        results[6][29]="3.503820798338526E-27";
+        results[6][30]="0.001639167241274031";
+        results[6][31]="4.275139211600108E-32";
+        results[6][32]="3.332513055029883E-8";
+        results[6][33]="1.839533197662788E-37";
+        results[6][34]="8.816353178189703E-13";
+        results[6][35]="2.164216619696854E-21";
+        results[6][36]="456039546753.1217";
+        results[6][37]="1.831097902883797E-26";
+        results[6][38]="2231887.195695002";
+        results[6][39]="1.951581054792877E-31";
+        results[6][40]="40.46608073162718";
+        results[6][41]="3.124447988106234E-36";
+        results[6][42]="0.0001461381098851545";
+        results[6][43]="5.636396886267384E-41";
+        results[6][44]="3.838931922393911E-9";
+        results[6][45]="4.943972717149220E-25";
+        results[6][46]="2691790295382633";
+        results[6][47]="1.797261089573547E-30";
+        results[6][48]="22289632225.11453";
+        results[6][49]="7.611519039226468E-35";
+        results[6][50]="751192.8010897827";
+        results[6][51]="1.894571918364917E-40";
+        results[6][52]="13.46049560925206";
+        results[6][53]="3.946403445450303E-45";
+        results[6][54]="0.00005489342032839216";
+        results[6][55]="1.998733821046708E-29";
+        results[6][56]="2.307230089645316E+19";
+        results[6][57]="2.004753620364024E-34";
+        results[6][58]="184413931005301.8";
+        results[6][59]="3.933634120896147E-39";
+        results[6][60]="9525266000.626017";
+        results[6][61]="1.818397779202506E-44";
+        results[6][62]="68100.11491666482";
+        results[6][63]="1.546614755106283E-49";
+        results[6][64]="0.7115725916931837";
+        results[6][65]="1.678025157975551E-33";
+        results[6][66]="1.495977592452194E+23";
+        results[6][67]="5.416686782253186E-38";
+        results[6][68]="3.191451493718201E+18";
+        results[6][69]="2.405835887289389E-43";
+        results[6][70]="23432555792739.37";
+        results[6][71]="1.470276429990037E-48";
+        results[6][72]="571130165.8104760";
+        results[6][73]="2.786013989610011E-53";
+        results[6][74]="1595.100155404736";
+        results[7][0]="8323411032.456378";
+        results[7][1]="18302.19115320239";
+        results[7][2]="0.4106420642242513";
+        results[7][3]="0.000004788534360528390";
+        results[7][4]="3.342244825091065E-11";
+        results[7][5]="104275.9649224148";
+        results[7][6]="64802737685647.92";
+        results[7][7]="1";
+        results[7][8]="95531442.66270503";
+        results[7][9]="0.000009321428998035992";
+        results[7][10]="3401.914291900572";
+        results[7][11]="1.129584707779182E-10";
+        results[7][12]="0.01516724885301000";
+        results[7][13]="1.421208568140421E-15";
+        results[7][14]="1.142756700777198E-7";
+        results[7][15]="12.27602131180330";
+        results[7][16]="1.410270050396740E+17";
+        results[7][17]="0.0001452906316467887";
+        results[7][18]="1106797349549.367";
+        results[7][19]="9.364654363655727E-10";
+        results[7][20]="37454892.83737830";
+        results[7][21]="1.746043504699232E-14";
+        results[7][22]="215.1782848775914";
+        results[7][23]="1.913677596875906E-19";
+        results[7][24]="0.001139773198646432";
+        results[7][25]="0.001140988851392383";
+        results[7][26]="3.056107864896266E+21";
+        results[7][27]="1.330140669811724E-8";
+        results[7][28]="4.713204612344845E+16";
+        results[7][29]="2.270571800922490E-13";
+        results[7][30]="106222524759.1882";
+        results[7][31]="2.770407248989495E-18";
+        results[7][32]="2159559.693390987";
+        results[7][33]="1.192067872721828E-23";
+        results[7][34]="57.13238223502557";
+        results[7][35]="1.402471619011349E-7";
+        results[7][36]="2.955261112252432E+25";
+        results[7][37]="1.186601570773187E-12";
+        results[7][38]="1.446324004865796E+20";
+        results[7][39]="1.264677951660229E-17";
+        results[7][40]="2622312814817888";
+        results[7][41]="2.024727833856987E-22";
+        results[7][42]="9470149600.764056";
+        results[7][43]="3.652539489129880E-27";
+        results[7][44]="248773.2983599527";
+        results[7][45]="3.203829671144209E-11";
+        results[7][46]="1.744353804164535E+29";
+        results[7][47]="1.164674389402563E-16";
+        results[7][48]="1.444429190193662E+24";
+        results[7][49]="4.932472716883077E-21";
+        results[7][50]="4.867935004036829E+19";
+        results[7][51]="1.227734470523965E-26";
+        results[7][52]="872276966085176.7";
+        results[7][53]="2.557377472772532E-31";
+        results[7][54]="3557243918.208811";
+        results[7][55]="1.295234235087226E-15";
+        results[7][56]="1.495148262797194E+33";
+        results[7][57]="1.299135229848029E-20";
+        results[7][58]="1.195052759651575E+28";
+        results[7][59]="2.549102600877473E-25";
+        results[7][60]="6.172633140245884E+23";
+        results[7][61]="1.178371542938247E-30";
+        results[7][62]="4.413073883307109E+18";
+        results[7][63]="1.002248702759050E-35";
+        results[7][64]="46111852003790.03";
+        results[7][65]="1.087406241422075E-19";
+        results[7][66]="9.694344350728666E+36";
+        results[7][67]="3.510161326756695E-24";
+        results[7][68]="2.068147939838898E+32";
+        results[7][69]="1.559047519187323E-29";
+        results[7][70]="1.518493766341199E+27";
+        results[7][71]="9.527793781803528E-35";
+        results[7][72]="3.701079831937688E+22";
+        results[7][73]="1.805413337572430E-39";
+        results[7][74]="1.033668569530294E+17";
+        results[8][0]="87.12745040231444";
+        results[8][1]="0.0001915829034197918";
+        results[8][2]="4.298501653263149E-9";
+        results[8][3]="5.012521769858929E-14";
+        results[8][4]="3.498580919469208E-19";
+        results[8][5]="0.001091535540718088";
+        results[8][6]="678339.3601041740";
+        results[8][7]="1.046775775731475E-8";
+        results[8][8]="1";
+        results[8][9]="9.757446070344992E-14";
+        results[8][10]="0.00003561041471876213";
+        results[8][11]="1.182421908739965E-18";
+        results[8][12]="1.587670868382187E-10";
+        results[8][13]="1.487686701391408E-23";
+        results[8][14]="1.196210031928393E-15";
+        results[8][15]="1.285024173155902E-7";
+        results[8][16]="1476236525.994914";
+        results[8][17]="1.520867136485833E-12";
+        results[8][18]="11585.68654152080";
+        results[8][19]="9.802693335972867E-18";
+        results[8][20]="0.3920687450478594";
+        results[8][21]="1.827716044092442E-22";
+        results[8][22]="0.000002252434160733091";
+        results[8][23]="2.003191350969721E-27";
+        results[8][24]="1.193086974171064E-11";
+        results[8][25]="1.194359490017227E-11";
+        results[8][26]="31990596809958.51";
+        results[8][27]="1.392359031474151E-16";
+        results[8][28]="493366841.4268441";
+        results[8][29]="2.376779558264652E-21";
+        results[8][30]="1111.911657549550";
+        results[8][31]="2.899995197153080E-26";
+        results[8][32]="0.02260574773287777";
+        results[8][33]="1.247827772192961E-31";
+        results[8][34]="5.980479373345604E-7";
+        results[8][35]="1.468073316931983E-15";
+        results[8][36]="3.093495743267101E+17";
+        results[8][37]="1.242105779730290E-20";
+        results[8][38]="1513976932152.447";
+        results[8][39]="1.323834243899629E-25";
+        results[8][40]="27449735.30941583";
+        results[8][41]="2.119436048930757E-30";
+        results[8][42]="99.13123194632914";
+        results[8][43]="3.823389857123776E-35";
+        results[8][44]="0.002604098623720172";
+        results[8][45]="3.353691289323497E-19";
+        results[8][46]="1.825947306504481E+21";
+        results[8][47]="1.219152937441450E-24";
+        results[8][48]="1.511993486054156E+16";
+        results[8][49]="5.163192954489619E-29";
+        results[8][50]="509563644006.1053";
+        results[8][51]="1.285162702774995E-34";
+        results[8][52]="9130783.978265085";
+        results[8][53]="2.677000787899666E-39";
+        results[8][54]="37.23636761949100";
+        results[8][55]="1.355819821187394E-23";
+        results[8][56]="1.565084982623100E+25";
+        results[8][57]="1.359903288004258E-28";
+        results[8][58]="1.250952279524317E+20";
+        results[8][59]="2.668338852452637E-33";
+        results[8][60]="6461362843686697";
+        results[8][61]="1.233490785959079E-38";
+        results[8][62]="46194988375.59113";
+        results[8][63]="1.049129663306469E-43";
+        results[8][64]="482687.6965168229";
+        results[8][65]="1.138270511899841E-27";
+        results[8][66]="1.014780482794204E+29";
+        results[8][67]="3.674351845758363E-32";
+        results[8][68]="2.164887164052315E+24";
+        results[8][69]="1.631973176299542E-37";
+        results[8][70]="1.589522490205218E+19";
+        results[8][71]="9.973463726956913E-43";
+        results[8][72]="387420071212069.1";
+        results[8][73]="1.889862946953332E-47";
+        results[8][74]="1082019218.719317";
+        results[9][0]="892932943458573.4";
+        results[9][1]="1963453367.188511";
+        results[9][2]="44053.55276650961";
+        results[9][3]="0.5137124749367641";
+        results[9][4]="0.000003585549839831714";
+        results[9][5]="11186693042.92137";
+        results[9][6]="6.952017517839994E+18";
+        results[9][7]="107279.6885767942";
+        results[9][8]="10248583418146.87";
+        results[9][9]="1";
+        results[9][10]="364956305.8000387";
+        results[9][11]="0.00001211814956716597";
+        results[9][12]="1627.137733517652";
+        results[9][13]="1.524668125927760E-10";
+        results[9][14]="0.01225945829784226";
+        results[9][15]="1316967.743292346";
+        results[9][16]="1.512933318157422E+22";
+        results[9][17]="15.58673371619321";
+        results[9][18]="1.187368749772774E+17";
+        results[9][19]="0.0001004637203762303";
+        results[9][20]="4018149239271.144";
+        results[9][21]="1.873150034256679E-9";
+        results[9][22]="23084259.39015671";
+        results[9][23]="2.052987366292351E-14";
+        results[9][24]="122.2745137989658";
+        results[9][25]="122.4049286469690";
+        results[9][26]="3.278583000031628E+26";
+        results[9][27]="0.001426970768207302";
+        results[9][28]="5.056311230110650E+21";
+        results[9][29]="2.435862356942155E-8";
+        results[9][30]="1.139551937600652E+16";
+        results[9][31]="2.972084269024861E-13";
+        results[9][32]="231676891369.9822";
+        results[9][33]="1.278846701479992E-18";
+        results[9][34]="6129144.173823912";
+        results[9][35]="0.01504567185253299";
+        results[9][36]="3.170394917855513E+30";
+        results[9][37]="1.272982469772824E-7";
+        results[9][38]="1.551611888231443E+25";
+        results[9][39]="1.356742568040473E-12";
+        results[9][40]="2.813209021245996E+20";
+        results[9][41]="2.172121714689447E-17";
+        results[9][42]="1015954699945620";
+        results[9][43]="3.918432989082965E-22";
+        results[9][44]="26688321974.27763";
+        results[9][45]="0.000003437058493734438";
+        results[9][46]="1.871337328785176E+34";
+        results[9][47]="1.249459057884749E-11";
+        results[9][48]="1.549579136952070E+29";
+        results[9][49]="5.291541369807505E-16";
+        results[9][50]="5.222305512451464E+24";
+        results[9][51]="1.317109716528063E-21";
+        results[9][52]="9.357760127432864E+19";
+        results[9][53]="2.743546588523462E-26";
+        results[9][54]="381620019737136.4";
+        results[9][55]="1.389523253741598E-10";
+        results[9][56]="1.603990400090178E+38";
+        results[9][57]="1.393708228772385E-15";
+        results[9][58]="1.282048878882594E+33";
+        results[9][59]="2.734669331724314E-20";
+        results[9][60]="6.621981609843777E+28";
+        results[9][61]="1.264153321541716E-25";
+        results[9][62]="4.734331918675705E+23";
+        results[9][63]="1.075209287084869E-30";
+        results[9][64]="4.946865122665819E+18";
+        results[9][65]="1.166566029362225E-14";
+        results[9][66]="1.040006242902376E+42";
+        results[9][67]="3.765690139887650E-19";
+        results[9][68]="2.218702669166555E+37";
+        results[9][69]="1.672541323348396E-24";
+        results[9][70]="1.629035383588871E+32";
+        results[9][71]="1.022138749735799E-29";
+        results[9][72]="3.970506917681290E+27";
+        results[9][73]="1.936841806071609E-34";
+        results[9][74]="1.108916422308302E+22";
+        results[10][0]="2446684.518852554";
+        results[10][1]="5.379968330412397";
+        results[10][2]="0.0001207091152184304";
+        results[10][3]="1.407599942164664E-9";
+        results[10][4]="9.824600322966481E-15";
+        results[10][5]="30.65214346248511";
+        results[10][6]="19048903683.41529";
+        results[10][7]="0.0002939521440563168";
+        results[10][8]="28081.67239549524";
+        results[10][9]="2.740054039641405E-9";
+        results[10][10]="1";
+        results[10][11]="3.320438467449187E-14";
+        results[10][12]="0.000004458445319778002";
+        results[10][13]="4.177673057560849E-19";
+        results[10][14]="3.359157823281803E-11";
+        results[10][15]="0.003608562785085618";
+        results[10][16]="41455190501253.18";
+        results[10][17]="4.270849268387010E-8";
+        results[10][18]="325345453.9358852";
+        results[10][19]="2.752760228542944E-13";
+        results[10][20]="11009.94605494694";
+        results[10][21]="5.132532318219450E-18";
+        results[10][22]="0.06325211819412893";
+        results[10][23]="5.625296326342124E-23";
+        results[10][24]="3.350387754800450E-7";
+        results[10][25]="3.353961192111453E-7";
+        results[10][26]="8.983494593536299E+17";
+        results[10][27]="3.909977017876616E-12";
+        results[10][28]="13854566011748.89";
+        results[10][29]="6.674394491149785E-17";
+        results[10][30]="31224338.90003856";
+        results[10][31]="8.143671507496243E-22";
+        results[10][32]="634.8072020898827";
+        results[10][33]="3.504109070472339E-27";
+        results[10][34]="0.01679418625303079";
+        results[10][35]="4.122595393865199E-11";
+        results[10][36]="8.687053401928578E+21";
+        results[10][37]="3.488040758693718E-16";
+        results[10][38]="4.251500422304194E+16";
+        results[10][39]="3.717547954312753E-21";
+        results[10][40]="770834474302.0734";
+        results[10][41]="5.951730878927634E-26";
+        results[10][42]="2783770.779678667";
+        results[10][43]="1.073671814080092E-30";
+        results[10][44]="73.12744443686990";
+        results[10][45]="9.417726010240848E-15";
+        results[10][46]="5.127565407269577E+25";
+        results[10][47]="3.423585338923651E-20";
+        results[10][48]="4.245930573949562E+20";
+        results[10][49]="1.449910930627067E-24";
+        results[10][50]="1.430939931563421E+16";
+        results[10][51]="3.608951799423663E-30";
+        results[10][52]="256407684391.6768";
+        results[10][53]="7.517465912828107E-35";
+        results[10][54]="1045659.476688773";
+        results[10][55]="3.807368804590335E-19";
+        results[10][56]="4.395020375313125E+29";
+        results[10][57]="3.818835862329240E-24";
+        results[10][58]="3.512883209599986E+24";
+        results[10][59]="7.493141749474667E-29";
+        results[10][60]="1.814458746048353E+20";
+        results[10][61]="3.463848415416480E-34";
+        results[10][62]="1297232529877061";
+        results[10][63]="2.946131550536850E-39";
+        results[10][64]="13554677762.92165";
+        results[10][65]="3.196453961262399E-23";
+        results[10][66]="2.849673307116934E+33";
+        results[10][67]="1.031819447983696E-27";
+        results[10][68]="6.079365211412986E+28";
+        results[10][69]="4.582853609507953E-33";
+        results[10][70]="4.463644983521472E+23";
+        results[10][71]="2.800715410287590E-38";
+        results[10][72]="1.087940351921676E+19";
+        results[10][73]="5.307051214872866E-43";
+        results[10][74]="30384909225705.58";
+        results[11][0]="7.368558528753992E+19";
+        results[11][1]="162025840356721.7";
+        results[11][2]="3635336609.961668";
+        results[11][3]="42391.98997251724";
+        results[11][4]="0.2958826196985332";
+        results[11][5]="923135416089567.4";
+        results[11][6]="5.736863932325467E+23";
+        results[11][7]="8852811065.104166";
+        results[11][8]="8.457218126697593E+17";
+        results[11][9]="82520.84977639587";
+        results[11][10]="30116504485873.39";
+        results[11][11]="1";
+        results[11][12]="134272788.4731154";
+        results[11][13]="0.00001258169093785437";
+        results[11][14]="1011.660916536231";
+        results[11][15]="108677297304.5868";
+        results[11][16]="1.248485430693727E+27";
+        results[11][17]="1286230.511498665";
+        results[11][18]="9.798267822918602E+21";
+        results[11][19]="8.290351577144743";
+        results[11][20]="3.315810897530334E+17";
+        results[11][21]="0.0001545739325855462";
+        results[11][22]="1904932701334.478";
+        results[11][23]="1.694142620466497E-9";
+        results[11][24]="10090196.78468630";
+        results[11][25]="10100958.72876698";
+        results[11][26]="2.705514552250553E+31";
+        results[11][27]="117.7548403985430";
+        results[11][28]="4.172510994426643E+26";
+        results[11][29]="0.002010094316332011";
+        results[11][30]="9.403679425514422E+20";
+        results[11][31]="2.452589194869899E-8";
+        results[11][32]="1.911817394940469E+16";
+        results[11][33]="1.055315165398698E-13";
+        results[11][34]="505782185625.9951";
+        results[11][35]="1241.581626727822";
+        results[11][36]="2.616236827482037E+35";
+        results[11][37]="0.01050475951561086";
+        results[11][38]="1.280403315400169E+30";
+        results[11][39]="1.119595496425095E-7";
+        results[11][40]="2.321483990318425E+25";
+        results[11][41]="1.792453297139352E-12";
+        results[11][42]="8.383744517383584E+19";
+        results[11][43]="3.233524200509892E-17";
+        results[11][44]="2202343008423450";
+        results[11][45]="0.2836289876341450";
+        results[11][46]="1.544243465896434E+39";
+        results[11][47]="0.000001031064232174645";
+        results[11][48]="1.278725871770590E+34";
+        results[11][49]="4.366624904634691E-11";
+        results[11][50]="4.309490886794513E+29";
+        results[11][51]="1.086890130566436E-16";
+        results[11][52]="7.722103177194344E+24";
+        results[11][53]="2.263997958860880E-21";
+        results[11][54]="3.149160832039346E+19";
+        results[11][55]="0.00001146646396828192";
+        results[11][56]="1.323626508486227E+43";
+        results[11][57]="1.150099873786527E-10";
+        results[11][58]="1.057957629402673E+38";
+        results[11][59]="2.256672371113390E-15";
+        results[11][60]="5.464515496479744E+33";
+        results[11][61]="1.043190063412758E-20";
+        results[11][62]="3.906810930526339E+28";
+        results[11][63]="8.872718405771617E-26";
+        results[11][64]="4.082195136515981E+23";
+        results[11][65]="9.626602006324680E-10";
+        results[11][66]="8.582219893706080E+46";
+        results[11][67]="3.107479503381239E-14";
+        results[11][68]="1.830892296607818E+42";
+        results[11][69]="1.380195312888473E-19";
+        results[11][70]="1.344293841695707E+37";
+        results[11][71]="8.434775821758094E-25";
+        results[11][72]="3.276496048901183E+32";
+        results[11][73]="1.598298317194785E-29";
+        results[11][74]="9.150872549988179E+26";
+        results[12][0]="548775266570.8102";
+        results[12][1]="1206691.558276256";
+        results[12][2]="27.07426166761666";
+        results[12][3]="0.0003157154212300068";
+        results[12][4]="2.203593319712548E-9";
+        results[12][5]="6875074.440525237";
+        results[12][6]="4272543973773303";
+        results[12][7]="65.93153509191260";
+        results[12][8]="6298534664.297173";
+        results[12][9]="0.0006145761230907817";
+        results[12][10]="224293.4315161216";
+        results[12][11]="7.447525380023099E-9";
+        results[12][12]="1";
+        results[12][13]="9.370246258327704E-14";
+        results[12][14]="0.000007534370351881011";
+        results[12][15]="809.3769299082260";
+        results[12][16]="9.298126931680603E+18";
+        results[12][17]="0.009579234378946397";
+        results[12][18]="72972848291449.96";
+        results[12][19]="6.174260378010000E-8";
+        results[12][20]="2469458581.471433";
+        results[12][21]="1.151193286020835E-12";
+        results[12][22]="14187.03464042448";
+        results[12][23]="1.261717016330308E-17";
+        results[12][24]="0.07514699664337871";
+        results[12][25]="0.07522714649505796";
+        results[12][26]="2.014938829390782E+23";
+        results[12][27]="8.769821624887181E-7";
+        results[12][28]="3.107488152941784E+18";
+        results[12][29]="1.497022843712283E-11";
+        results[12][30]="7003414118711.969";
+        results[12][31]="1.826572027556399E-16";
+        results[12][32]="142383085.7078879";
+        results[12][33]="7.859486478230080E-22";
+        results[12][34]="3766.825664213152";
+        results[12][35]="0.000009246710676425823";
+        results[12][36]="1.948449017282359E+27";
+        results[12][37]="7.823446310355102E-11";
+        results[12][38]="9.535836188108477E+21";
+        results[12][39]="8.338215874985453E-16";
+        results[12][40]="1.728931093721377E+17";
+        results[12][41]="1.334934142295141E-20";
+        results[12][42]="624381500728.4375";
+        results[12][43]="2.408175355021632E-25";
+        results[12][44]="16402005.45075007";
+        results[12][45]="2.112334083915552E-9";
+        results[12][46]="1.150079240519853E+31";
+        results[12][47]="7.678877037554697E-15";
+        results[12][48]="9.523343384103629E+25";
+        results[12][49]="3.252054980230781E-19";
+        results[12][50]="3.209504275438039E+21";
+        results[12][51]="8.094641832690152E-25";
+        results[12][52]="5.751055939931189E+16";
+        results[12][53]="1.686118225893689E-29";
+        results[12][54]="234534552223.8769";
+        results[12][55]="8.539678142289999E-14";
+        results[12][56]="9.857742015622534E+34";
+        results[12][57]="8.565397999586525E-19";
+        results[12][58]="7.879166295965479E+29";
+        results[12][59]="1.680662475826388E-23";
+        results[12][60]="4.069711784956242E+25";
+        results[12][61]="7.769184473454425E-29";
+        results[12][62]="2.909607356004657E+20";
+        results[12][63]="6.607979551678220E-34";
+        results[12][64]="3040225188540963";
+        results[12][65]="7.169436276548434E-18";
+        results[12][66]="6.391630047531518E+38";
+        results[12][67]="2.314303246933335E-22";
+        results[12][68]="1.363561684707550E+34";
+        results[12][69]="1.027903962212583E-27";
+        results[12][70]="1.001166250423753E+29";
+        results[12][71]="6.281820700734860E-33";
+        results[12][72]="2.440178748173697E+24";
+        results[12][73]="1.190336728215637E-37";
+        results[12][74]="6.815135556539365E+18";
+        results[13][0]="5.856572510920854E+24";
+        results[13][1]="1.287790656733084E+19";
+        results[13][2]="288938635348614.2";
+        results[13][3]="3369339636.612199";
+        results[13][4]="23516.92003563011";
+        results[13][5]="7.337133145689837E+19";
+        results[13][6]="4.559692302618115E+28";
+        results[13][7]="703626492562206.3";
+        results[13][8]="6.721845393016666E+22";
+        results[13][9]="6558804391.555706";
+        results[13][10]="2.393677021207241E+18";
+        results[13][11]="79480.57259865707";
+        results[13][12]="10672078112261.57";
+        results[13][13]="1";
+        results[13][14]="80407388.92198187";
+        results[13][15]="8637733818243049";
+        results[13][16]="9.923033691261843E+31";
+        results[13][17]="102230337547.7774";
+        results[13][18]="7.787719370405676E+26";
+        results[13][19]="658921.8903956439";
+        results[13][20]="2.635425487645780E+22";
+        results[13][21]="12.28562467072543";
+        results[13][22]="1.514051418639709E+17";
+        results[13][23]="0.0001346514255384665";
+        results[13][24]="801974618079.9959";
+        results[13][25]="802829983557.8030";
+        results[13][26]="2.150358457868733E+36";
+        results[13][27]="9359222.141139671";
+        results[13][28]="3.316335630112216E+31";
+        results[13][29]="159.7634472393744";
+        results[13][30]="7.474098252740968E+25";
+        results[13][31]="0.001949331935575389";
+        results[13][32]="1.519523412539414E+21";
+        results[13][33]="8.387705361793504E-9";
+        results[13][34]="4.019985772375435E+16";
+        results[13][35]="98681618.62029944";
+        results[13][36]="2.079400011019663E+40";
+        results[13][37]="834.9243013119425";
+        results[13][38]="1.017671886652243E+35";
+        results[13][39]="0.008898609113474424";
+        results[13][40]="1.845128768291237E+30";
+        results[13][41]="1.424652144129865E-7";
+        results[13][42]="6.663448147624991E+24";
+        results[13][43]="2.570023549681410E-12";
+        results[13][44]="1.750434833681448E+20";
+        results[13][45]="22542.99434273927";
+        results[13][46]="1.227373549011834E+44";
+        results[13][47]="0.08194957555923548";
+        results[13][48]="1.016338644850434E+39";
+        results[13][49]="0.000003470618477439216";
+        results[13][50]="3.425208032911223E+34";
+        results[13][51]="8.638664992924948E-12";
+        results[13][52]="6.137571821893155E+29";
+        results[13][53]="1.799438541324536E-16";
+        results[13][54]="2.502971061357505E+24";
+        results[13][55]="0.9113611218809168";
+        results[13][56]="1.052025928012465E+48";
+        results[13][57]="0.000009141059651419642";
+        results[13][58]="8.408707817004228E+42";
+        results[13][59]="1.793616122236614E-10";
+        results[13][60]="4.343228206344449E+38";
+        results[13][61]="8.291334356927543E-16";
+        results[13][62]="3.105155697929257E+33";
+        results[13][63]="7.052087393973718E-21";
+        results[13][64]="3.244552069097433E+28";
+        results[13][65]="0.00007651278396420666";
+        results[13][66]="6.821197513193451E+51";
+        results[13][67]="2.469842502673314E-9";
+        results[13][68]="1.455203681008597E+47";
+        results[13][69]="1.096987137663585E-14";
+        results[13][70]="1.068452442788232E+42";
+        results[13][71]="6.704008120546416E-20";
+        results[13][72]="2.604177820839036E+37";
+        results[13][73]="1.270336654341115E-24";
+        results[13][74]="7.273165900503936E+31";
+        results[14][0]="7.283624788019671E+16";
+        results[14][1]="160158248389.6609";
+        results[14][2]="3593433.877438394";
+        results[14][3]="41.90335840753915";
+        results[14][4]="0.0002924721266406031";
+        results[14][5]="912494889345.1759";
+        results[14][6]="5.670737930617694E+20";
+        results[14][7]="8750769.077266332";
+        results[14][8]="835973594359440.8";
+        results[14][9]="81.56967263194704";
+        results[14][10]="29769366389.07392";
+        results[14][11]="0.0009884734930986993";
+        results[14][12]="132725.0922501232";
+        results[14][13]="1.243666799042916E-8";
+        results[14][14]="1";
+        results[14][15]="107424627.6871908";
+        results[14][16]="1.234094754760663E+24";
+        results[14][17]="1271.404766631212";
+        results[14][18]="9.685328021236938E+18";
+        results[14][19]="0.008194792782476575";
+        results[14][20]="327759118033654.3";
+        results[14][21]="1.527922350848377E-7";
+        results[14][22]="1882975481.406032";
+        results[14][23]="1.674615073859902E-12";
+        results[14][24]="9973.892061812134";
+        results[14][25]="9984.529958270096";
+        results[14][26]="2.674329420092467E+28";
+        results[14][27]="0.1163975384180276";
+        results[14][28]="4.124416517653632E+23";
+        results[14][29]="0.000001986924950322545";
+        results[14][30]="9.295287849718610E+17";
+        results[14][31]="2.424319408589176E-11";
+        results[14][32]="18897808185436.61";
+        results[14][33]="1.043151067861683E-16";
+        results[14][34]="499952283.7728221";
+        results[14][35]="1.227270527538816";
+        results[14][36]="2.586080755634628E+32";
+        results[14][37]="0.00001038367633255766";
+        results[14][38]="1.265644737748760E+27";
+        results[14][39]="1.106690471208886E-10";
+        results[14][40]="2.294725389082761E+22";
+        results[14][41]="1.771792571839617E-15";
+        results[14][42]="8.287109228345220E+16";
+        results[14][43]="3.196252961497192E-20";
+        results[14][44]="2176957686537.825";
+        results[14][45]="0.0002803597361507711";
+        results[14][46]="1.526443732929490E+36";
+        results[14][47]="1.019179663186800E-9";
+        results[14][48]="1.263986629184754E+31";
+        results[14][49]="4.316292972536028E-14";
+        results[14][50]="4.259817510346784E+26";
+        results[14][51]="1.074362083975506E-19";
+        results[14][52]="7.633094301629857E+21";
+        results[14][53]="2.237901970763539E-24";
+        results[14][54]="3.112862007975538E+16";
+        results[14][55]="1.133429569221800E-8";
+        results[14][56]="1.308369718401416E+40";
+        results[14][57]="1.136843239654142E-13";
+        results[14][58]="1.045763073486079E+35";
+        results[14][59]="2.230660821453777E-18";
+        results[14][60]="5.401528720897306E+30";
+        results[14][61]="1.031165725947463E-23";
+        results[14][62]="3.861779047373550E+25";
+        results[14][63]="8.770446955834192E-29";
+        results[14][64]="4.035141686102474E+20";
+        results[14][65]="9.515640911862703E-13";
+        results[14][66]="8.483296876872797E+43";
+        results[14][67]="3.071661119439865E-17";
+        results[14][68]="1.809788503915430E+39";
+        results[14][69]="1.364286482089321E-22";
+        results[14][70]="1.328798829452025E+34";
+        results[14][71]="8.337552320037675E-28";
+        results[14][72]="3.238729494581439E+29";
+        results[14][73]="1.579875520611302E-32";
+        results[14][74]="9.045394954387817E+23";
+        results[15][0]="678021878.6728144";
+        results[15][1]="1490.889490034119";
+        results[15][2]="0.03345074546501661";
+        results[15][3]="3.900721772064906E-7";
+        results[15][4]="2.722579849122226E-12";
+        results[15][5]="8494.280212934647";
+        results[15][6]="5278806222284.789";
+        results[15][7]="0.08145961746078984";
+        results[15][8]="7781954.774781330";
+        results[15][9]="7.593200403679254E-7";
+        results[15][10]="277.1186368526144";
+        results[15][11]="9.201553818525026E-12";
+        results[15][12]="0.001235518289498798";
+        results[15][13]="1.157711062927156E-16";
+        results[15][14]="9.308852369606484E-9";
+        results[15][15]="1";
+        results[15][16]="1.148800588217273E+16";
+        results[15][17]="0.00001183531927458393";
+        results[15][18]="90159288700.90755";
+        results[15][19]="7.628411621159118E-11";
+        results[15][20]="3051061.242567714";
+        results[15][21]="1.422320359626963E-15";
+        results[15][22]="17.52834077199745";
+        results[15][23]="1.558874449847949E-20";
+        results[15][24]="0.00009284548875379919";
+        results[15][25]="0.00009294451536144952";
+        results[15][26]="2.489493775933610E+20";
+        results[15][27]="1.083527501319018E-9";
+        results[15][28]="3839358447360413";
+        results[15][29]="1.849599103204027E-14";
+        results[15][30]="8652846232.602745";
+        results[15][31]="2.256763147132834E-19";
+        results[15][32]="175916.9065073704";
+        results[15][33]="9.710539289921761E-25";
+        results[15][34]="4.653982001488808";
+        results[15][35]="1.142448015842791E-8";
+        results[15][36]="2.407344397008314E+24";
+        results[15][37]="9.666011003355619E-14";
+        results[15][38]="1.178170001607253E+19";
+        results[15][39]="1.030201821533375E-18";
+        results[15][40]="213612598757592.2";
+        results[15][41]="1.649335548082038E-23";
+        results[15][42]="771434763.7746916";
+        results[15][43]="2.975344695449488E-28";
+        results[15][44]="20264.97771886068";
+        results[15][45]="2.609827394209354E-12";
+        results[15][46]="1.420943936035166E+28";
+        results[15][47]="9.487393022711177E-18";
+        results[15][48]="1.176626492823741E+23";
+        results[15][49]="4.017973406530782E-22";
+        results[15][50]="3.965401232528285E+18";
+        results[15][51]="1.000107803123075E-27";
+        results[15][52]="71055347977156.85";
+        results[15][53]="2.083229906348919E-32";
+        results[15][54]="289771728.7920109";
+        results[15][55]="1.055092853123241E-16";
+        results[15][56]="1.217942055346239E+32";
+        results[15][57]="1.058270588532557E-21";
+        results[15][58]="9.734854064667849E+26";
+        results[15][59]="2.076489227357834E-26";
+        results[15][60]="5.028203343302236E+22";
+        results[15][61]="9.598969511443032E-32";
+        results[15][62]="3.594873103603994E+17";
+        results[15][63]="8.164279592732510E-37";
+        results[15][64]="3756253824637.292";
+        results[15][65]="8.857969645071753E-21";
+        results[15][66]="7.896975823435262E+35";
+        results[15][67]="2.859363989032589E-25";
+        results[15][68]="1.684705400315972E+31";
+        results[15][69]="1.269994145161927E-30";
+        results[15][70]="1.236959213227480E+26";
+        results[15][71]="7.761304367110075E-36";
+        results[15][72]="3.014885473014884E+21";
+        results[15][73]="1.470682798372580E-40";
+        results[15][74]="8420224625517956";
+        results[16][0]="5.901998011029744E-8";
+        results[16][1]="1.297779184068582E-13";
+        results[16][2]="2.911797383123386E-18";
+        results[16][3]="3.395473341564099E-23";
+        results[16][4]="2.369932499205253E-28";
+        results[16][5]="7.394042360403217E-13";
+        results[16][6]="0.0004595058773843880";
+        results[16][7]="7.090840507594115E-18";
+        results[16][8]="6.773982233816134E-10";
+        results[16][9]="6.609676632793603E-23";
+        results[16][10]="2.412243166437193E-14";
+        results[16][11]="8.009705002679486E-28";
+        results[16][12]="1.075485425556837E-19";
+        results[16][13]="1.007756328470993E-32";
+        results[16][14]="8.103105504195564E-25";
+        results[16][15]="8.704730918982346E-17";
+        results[16][16]="1";
+        results[16][17]="1.030232696254985E-21";
+        results[16][18]="0.000007848123479882456";
+        results[16][19]="6.640327050142802E-27";
+        results[16][20]="2.655866713388787E-10";
+        results[16][21]="1.238091601114291E-31";
+        results[16][22]="1.525794898764651E-15";
+        results[16][23]="1.356958262240303E-36";
+        results[16][24]="8.081949966432234E-21";
+        results[16][25]="8.090569966166392E-21";
+        results[16][26]="21670.37344398340";
+        results[16][27]="9.431815342299341E-26";
+        results[16][28]="0.3342058218579424";
+        results[16][29]="1.610026250138211E-30";
+        results[16][30]="7.532069813813702E-7";
+        results[16][31]="1.964451594366708E-35";
+        results[16][32]="1.531309335246434E-11";
+        results[16][33]="8.452763159697483E-41";
+        results[16][34]="4.051166102474697E-16";
+        results[16][35]="9.944702566836774E-25";
+        results[16][36]="209552852.0527718";
+        results[16][37]="8.414002484413322E-30";
+        results[16][38]="1025.565284080813";
+        results[16][39]="8.967629648693503E-35";
+        results[16][40]="0.01859440193089382";
+        results[16][41]="1.435702214116641E-39";
+        results[16][42]="6.715132040207400E-8";
+        results[16][43]="2.589957496510927E-44";
+        results[16][44]="1.764011781218549E-12";
+        results[16][45]="2.271784521158129E-28";
+        results[16][46]="1236893461414.578";
+        results[16][47]="8.258520338533136E-34";
+        results[16][48]="10242217.01217658";
+        results[16][49]="3.497537734347732E-38";
+        results[16][50]="345.1775071495967";
+        results[16][51]="8.705669316160942E-44";
+        results[16][52]="0.006185176844958069";
+        results[16][53]="1.813395577714413E-48";
+        results[16][54]="2.522384927062784E-8";
+        results[16][55]="9.184299380979178E-33";
+        results[16][56]="1.060185786670131E+16";
+        results[16][57]="9.211960712648993E-38";
+        results[16][58]="84739285168.49519";
+        results[16][59]="1.807527998031550E-42";
+        results[16][60]="4376915.710937338";
+        results[16][61]="8.355644669662702E-48";
+        results[16][62]="31.29240305475972";
+        results[16][63]="7.106785700207527E-53";
+        results[16][64]="0.0003269717880686592";
+        results[16][65]="7.710624224886317E-37";
+        results[16][66]="6.874104961671300E+19";
+        results[16][67]="2.488999412395668E-41";
+        results[16][68]="1466490718750697";
+        results[16][69]="1.105495730231758E-46";
+        results[16][70]="10767397108.90133";
+        results[16][71]="6.756006609601578E-52";
+        results[16][72]="262437.6679414338";
+        results[16][73]="1.280189802700927E-56";
+        results[16][74]="0.7329578964252270";
+        results[17][0]="57288009131181.63";
+        results[17][1]="125969520.1662847";
+        results[17][2]="2826.349225478968";
+        results[17][3]="0.03295831469829135";
+        results[17][4]="2.300385638914618E-7";
+        results[17][5]="717706047.1174538";
+        results[17][6]="4.460214464700500E+17";
+        results[17][7]="6882.756229121966";
+        results[17][8]="657519632063.7410";
+        results[17][9]="0.06415712350055034";
+        results[17][10]="23414546.78351770";
+        results[17][11]="7.774656183788081E-7";
+        results[17][12]="104.3924765216976";
+        results[17][13]="9.781832125249994E-12";
+        results[17][14]="0.0007865315800645127";
+        results[17][15]="84492.86215264814";
+        results[17][16]="9.706544974112313E+20";
+        results[17][17]="1";
+        results[17][18]="7617816351986589";
+        results[17][19]="0.000006445463315502565";
+        results[17][20]="257792896987.5612";
+        results[17][21]="1.201759180828659E-10";
+        results[17][22]="1481019.680613023";
+        results[17][23]="1.317137640042879E-15";
+        results[17][24]="7.844781082769998";
+        results[17][25]="7.853148124279642";
+        results[17][26]="2.103444544398340E+25";
+        results[17][27]="0.00009155033980755107";
+        results[17][28]="3.243983840474286E+20";
+        results[17][29]="1.562779220646795E-9";
+        results[17][30]="731103743959364.5";
+        results[17][31]="1.906803775018709E-14";
+        results[17][32]="14863722931.84754";
+        results[17][33]="8.204712576512332E-20";
+        results[17][34]="393228.2597126994";
+        results[17][35]="0.0009652870271917130";
+        results[17][36]="2.034034182903733E+29";
+        results[17][37]="8.167089352725064E-9";
+        results[17][38]="9.954695553818683E+23";
+        results[17][39]="8.704470049622648E-14";
+        results[17][40]="1.804873986089417E+19";
+        results[17][41]="1.393570811075580E-18";
+        results[17][42]="65180731155375.70";
+        results[17][43]="2.513953892092264E-23";
+        results[17][44]="1712245968.926182";
+        results[17][45]="2.205117862611359E-7";
+        results[17][46]="1.200596201140605E+33";
+        results[17][47]="8.016169908559313E-13";
+        results[17][48]="9.941654006331020E+27";
+        results[17][49]="3.394900731710114E-17";
+        results[17][50]="3.350480997199534E+23";
+        results[17][51]="8.450197074706576E-23";
+        results[17][52]="6.003669721842360E+18";
+        results[17][53]="1.760180573094133E-27";
+        results[17][54]="24483642736557.92";
+        results[17][55]="8.914781499718627E-12";
+        results[17][56]="1.029074101922827E+37";
+        results[17][57]="8.941631095708316E-17";
+        results[17][58]="8.225256825621270E+31";
+        results[17][59]="1.754485180486043E-21";
+        results[17][60]="4.248472919611204E+27";
+        results[17][61]="8.110444077378283E-27";
+        results[17][62]="3.037411175990747E+22";
+        results[17][63]="6.898233502044262E-32";
+        results[17][64]="3.173766366154361E+17";
+        results[17][65]="7.484352081733892E-16";
+        results[17][66]="6.672380896723107E+40";
+        results[17][67]="2.415958473695767E-20";
+        results[17][68]="1.423455811567193E+36";
+        results[17][69]="1.073054402418369E-25";
+        results[17][70]="1.045142242916776E+31";
+        results[17][71]="6.557748200149776E-31";
+        results[17][72]="2.547363026774680E+26";
+        results[17][73]="1.242621989531652E-35";
+        results[17][74]="7.114488785782220E+20";
+        results[18][0]="0.007520266502124582";
+        results[18][1]="1.653617183005917E-8";
+        results[18][2]="3.710182938109170E-13";
+        results[18][3]="4.326477979440449E-18";
+        results[18][4]="3.019744153210938E-23";
+        results[18][5]="9.421414404802356E-8";
+        results[18][6]="58.54977671570353";
+        results[18][7]="9.035077653620603E-13";
+        results[18][8]="0.00008631340028199442";
+        results[18][9]="8.421983483996608E-18";
+        results[18][10]="3.073655979828342E-9";
+        results[18][11]="1.020588555112725E-22";
+        results[18][12]="1.370372711787334E-14";
+        results[18][13]="1.284072977513965E-27";
+        results[18][14]="1.032489553071727E-19";
+        results[18][15]="1.109148058296442E-11";
+        results[18][16]="127418.9941790999";
+        results[18][17]="1.312712139272323E-16";
+        results[18][18]="1";
+        results[18][19]="8.461037937494653E-22";
+        results[18][20]="0.00003384078652937511";
+        results[18][21]="1.577563865155743E-26";
+        results[18][22]="1.944152513241934E-10";
+        results[18][23]="1.729022569176787E-31";
+        results[18][24]="1.029793935728606E-15";
+        results[18][25]="1.030892287424556E-15";
+        results[18][26]="2761217187.717842";
+        results[18][27]="1.201792424198785E-20";
+        results[18][28]="42584.16966993846";
+        results[18][29]="2.051479253945588E-25";
+        results[18][30]="0.09597287597629022";
+        results[18][31]="2.503084462677351E-30";
+        results[18][32]="0.000001951178952741667";
+        results[18][33]="1.077042579842804E-35";
+        results[18][34]="5.161955100297903E-11";
+        results[18][35]="1.267143998476655E-19";
+        results[18][36]="26701013635925.91";
+        results[18][37]="1.072103733584393E-24";
+        results[18][38]="130676496.9625801";
+        results[18][39]="1.142646350007201E-29";
+        results[18][40]="2369.279991396404";
+        results[18][41]="1.829357320634491E-34";
+        results[18][42]="0.008556353703430740";
+        results[18][43]="3.300097791720419E-39";
+        results[18][44]="2.247686068829500E-7";
+        results[18][45]="2.894684986776169E-23";
+        results[18][46]="1.576037207601508E+17";
+        results[18][47]="1.052292354943532E-28";
+        results[18][48]="1305052989855.606";
+        results[18][49]="4.456527402140359E-33";
+        results[18][50]="43982170.77425067";
+        results[18][51]="1.109267627921080E-38";
+        results[18][52]="788.1090124044157";
+        results[18][53]="2.310610405611983E-43";
+        results[18][54]="0.003213997503388622";
+        results[18][55]="1.170254189364097E-27";
+        results[18][56]="1.350878065804859E+21";
+        results[18][57]="1.173778768423119E-32";
+        results[18][58]="1.079739448362558E+16";
+        results[18][59]="2.303133994597421E-37";
+        results[18][60]="557702197494.3356";
+        results[18][61]="1.064667839526379E-42";
+        results[18][62]="3987246.522684476";
+        results[18][63]="9.055394857668533E-48";
+        results[18][64]="41.66241636065038";
+        results[18][65]="9.824799832280163E-32";
+        results[18][66]="8.758915400977171E+24";
+        results[18][67]="3.171458016398266E-36";
+        results[18][68]="1.868587723561991E+20";
+        results[18][69]="1.408611540154202E-41";
+        results[18][70]="1371970909543155";
+        results[18][71]="8.608435668627840E-47";
+        results[18][72]="33439543683.80610";
+        results[18][73]="1.631204970184925E-51";
+        results[18][74]="93392.75793813131";
+        results[19][0]="8.888113441495055E+18";
+        results[19][1]="19543904603925.69";
+        results[19][2]="438502104.0583787";
+        results[19][3]="5113.412812236528";
+        results[19][4]="0.03568999661175253";
+        results[19][5]="111350575123317.2";
+        results[19][6]="6.919928399829436E+22";
+        results[19][7]="1067845070.589050";
+        results[19][8]="1.020127801336300E+17";
+        results[19][9]="9953.842006398556";
+        results[19][10]="3632717407172.463";
+        results[19][11]="0.1206221462014772";
+        results[19][12]="16196271.92208414";
+        results[19][13]="0.000001517630563767670";
+        results[19][14]="122.0287109807536";
+        results[19][15]="13108888844.25527";
+        results[19][16]="1.505949921515530E+26";
+        results[19][17]="155147.8848067927";
+        results[19][18]="1.181888093857317E+21";
+        results[19][19]="1";
+        results[19][20]="3.999602268583552E+16";
+        results[19][21]="0.00001864503949527103";
+        results[19][22]="229777070804.3422";
+        results[19][23]="2.043511188520634E-10";
+        results[19][24]="1217101.191764106";
+        results[19][25]="1218399.320556418";
+        results[19][26]="3.263449718717902E+30";
+        results[19][27]="14.20384157448466";
+        results[19][28]="5.032972311970014E+25";
+        results[19][29]="0.0002424618905033581";
+        results[19][30]="1.134291994496223E+20";
+        results[19][31]="2.958365724357601E-9";
+        results[19][32]="2306075173230364";
+        results[19][33]="1.272943801693578E-14";
+        results[19][34]="61008532740.68144";
+        results[19][35]="149.7622405002312";
+        results[19][36]="3.155761011022271E+34";
+        results[19][37]="0.001267106638103371";
+        results[19][38]="1.544449959070552E+29";
+        results[19][39]="1.350480116563032E-8";
+        results[19][40]="2.800223812845777E+24";
+        results[19][41]="2.162095636668628E-13";
+        results[19][42]="1.011265256891675E+19";
+        results[19][43]="3.900346288599187E-18";
+        results[19][44]="265651340347854.4";
+        results[19][45]="0.03421193721338280";
+        results[19][46]="1.862699611140355E+38";
+        results[19][47]="1.243691805564838E-7";
+        results[19][48]="1.542426590563234E+33";
+        results[19][49]="5.267116676538570E-12";
+        results[19][50]="5.198200398008612E+28";
+        results[19][51]="1.311030202341272E-17";
+        results[19][52]="9.314566584224275E+23";
+        results[19][53]="2.730882927935629E-22";
+        results[19][54]="3.798585382942154E+18";
+        results[19][55]="0.000001383109493196072";
+        results[19][56]="1.596586702227764E+42";
+        results[19][57]="1.387275151221789E-11";
+        results[19][58]="1.276131198487774E+37";
+        results[19][59]="2.722046646772734E-16";
+        results[19][60]="6.591415871366172E+32";
+        results[19][61]="1.258318243449020E-21";
+        results[19][62]="4.712479192434771E+27";
+        results[19][63]="1.070246336745521E-26";
+        results[19][64]="4.924031385797897E+22";
+        results[19][65]="1.161181394630329E-10";
+        results[19][66]="1.035205782751841E+46";
+        results[19][67]="3.748308469749455E-15";
+        results[19][68]="2.208461582805865E+41";
+        results[19][69]="1.664821208178269E-20";
+        results[19][70]="1.621516083107649E+36";
+        results[19][71]="1.017420762348790E-25";
+        results[19][72]="3.952179854391208E+31";
+        results[19][73]="1.927901732902443E-30";
+        results[19][74]="1.103797886595758E+26";
+        results[20][0]="222.2249324966694";
+        results[20][1]="0.0004886462025847162";
+        results[20][2]="1.096364274774934E-8";
+        results[20][3]="1.278480326006873E-13";
+        results[20][4]="8.923386430719285E-19";
+        results[20][5]="0.002784041203245736";
+        results[20][6]="1730154.134120969";
+        results[20][7]="2.669878150077217E-8";
+        results[20][8]="2.550573114105107";
+        results[20][9]="2.488707960935246E-13";
+        results[20][10]="0.00009082696636380747";
+        results[20][11]="3.015853529960997E-18";
+        results[20][12]="4.049470630943514E-10";
+        results[20][13]="3.794453702780639E-23";
+        results[20][14]="3.051021146259370E-15";
+        results[20][15]="3.277548107026588E-7";
+        results[20][16]="3765249193.262553";
+        results[20][17]="3.879082828446787E-12";
+        results[20][18]="29550.14060125232";
+        results[20][19]="2.500248606854969E-17";
+        results[20][20]="1";
+        results[20][21]="4.661723402280728E-22";
+        results[20][22]="0.000005744998011657722";
+        results[20][23]="5.109286002191258E-27";
+        results[20][24]="3.043055559109729E-11";
+        results[20][25]="3.046301203814225E-11";
+        results[20][26]="81594356127656.76";
+        results[20][27]="3.551313510859396E-16";
+        results[20][28]="1258368201.134266";
+        results[20][29]="6.062150039464433E-21";
+        results[20][30]="2836.011979005927";
+        results[20][31]="7.396649780892585E-26";
+        results[20][32]="0.05765761239172050";
+        results[20][33]="3.182675966789038E-31";
+        results[20][34]="0.000001525364989911545";
+        results[20][35]="3.744428331701820E-15";
+        results[20][36]="7.890187071375662E+17";
+        results[20][37]="3.168081606654638E-20";
+        results[20][38]="3861508858523.363";
+        results[20][39]="3.376536030022057E-25";
+        results[20][40]="70012556.86949763";
+        results[20][41]="5.405776603467944E-30";
+        results[20][42]="252.8414549704244";
+        results[20][43]="9.751835374322068E-35";
+        results[20][44]="0.006641943936138782";
+        results[20][45]="8.553834835557002E-19";
+        results[20][46]="4.657212107742966E+21";
+        results[20][47]="3.109538704220428E-24";
+        results[20][48]="3.856449934231786E+16";
+        results[20][49]="1.316910113265814E-28";
+        results[20][50]="1299679330327.398";
+        results[20][51]="3.277901436948555E-34";
+        results[20][52]="23288732.12566459";
+        results[20][53]="6.827886236055077E-39";
+        results[20][54]="94.97407811720772";
+        results[20][55]="3.458117583491362E-23";
+        results[20][56]="3.991863677968137E+25";
+        results[20][57]="3.468532764166796E-28";
+        results[20][58]="3.190645251183220E+20";
+        results[20][59]="6.805793336387770E-33";
+        results[20][60]="1.648017834958501E+16";
+        results[20][61]="3.146108435163604E-38";
+        results[20][62]="117823695357.1807";
+        results[20][63]="2.675881912439624E-43";
+        results[20][64]="1231130.261245134";
+        results[20][65]="2.903242164230390E-27";
+        results[20][66]="2.588271816133498E+29";
+        results[20][67]="9.371703029553756E-32";
+        results[20][68]="5.521702995703085E+24";
+        results[20][69]="4.162466906410325E-37";
+        results[20][70]="4.054193327782826E+19";
+        results[20][71]="2.543804843647882E-42";
+        results[20][72]="988143217498189.4";
+        results[20][73]="4.820233621842614E-47";
+        results[20][74]="2759769128.210504";
+        results[21][0]="4.767012396916274E+23";
+        results[21][1]="1.048209343234839E+18";
+        results[21][2]="23518432565916.35";
+        results[21][3]="274250575.5235032";
+        results[21][4]="1914.181872385126";
+        results[21][5]="5.972128680744241E+18";
+        results[21][6]="3.711404527506926E+27";
+        results[21][7]="57272341571595.42";
+        results[21][8]="5.471309415005725E+21";
+        results[21][9]="533860065.5108917";
+        results[21][10]="1.948355973230217E+17";
+        results[21][11]="6469.396121798011";
+        results[21][12]="868663857010.9776";
+        results[21][13]="0.08139594255901624";
+        results[21][14]="6544835.210014115";
+        results[21][15]="703076485709783.2";
+        results[21][16]="8.076946803451319E+30";
+        results[21][17]="8321134682.827734";
+        results[21][18]="6.338887585392785E+25";
+        results[21][19]="53633.56834152223";
+        results[21][20]="2.145129416109833E+21";
+        results[21][21]="1";
+        results[21][22]="1.232376423029948E+16";
+        results[21][23]="0.00001096007969861868";
+        results[21][24]="65277479947.02833";
+        results[21][25]="65347103226.32689";
+        results[21][26]="1.750304535179781E+35";
+        results[21][27]="761802.7077972777";
+        results[21][28]="2.699362644550329E+30";
+        results[21][29]="13.00409637452654";
+        results[21][30]="6.083612720605475E+24";
+        results[21][31]="0.0001586677102565503";
+        results[21][32]="1.236830404041385E+20";
+        results[21][33]="6.827251838304966E-10";
+        results[21][34]="3272105310163334";
+        results[21][35]="8032283.360848641";
+        results[21][36]="1.692547238541742E+39";
+        results[21][37]="67.95945047071364";
+        results[21][38]="8.283436242987168E+33";
+        results[21][39]="0.0007243106762555027";
+        results[21][40]="1.501859952378219E+29";
+        results[21][41]="1.159609040901739E-8";
+        results[21][42]="5.423776426690670E+23";
+        results[21][43]="2.091894892251871E-13";
+        results[21][44]="1.424782931756363E+19";
+        results[21][45]="1834.908272629834";
+        results[21][46]="9.990322689382312E+42";
+        results[21][47]="0.006670362944955292";
+        results[21][48]="8.272584195675434E+37";
+        results[21][49]="2.824942622339028E-7";
+        results[21][50]="2.787980362995230E+33";
+        results[21][51]="7.031522795507035E-13";
+        results[21][52]="4.995734434666519E+28";
+        results[21][53]="1.464669961481319E-17";
+        results[21][54]="2.037316887371354E+23";
+        results[21][55]="0.07418109752713971";
+        results[21][56]="8.563064200709839E+46";
+        results[21][57]="7.440451663154942E-7";
+        results[21][58]="6.844346984684270E+41";
+        results[21][59]="1.459930748584969E-11";
+        results[21][60]="3.535211536043119E+37";
+        results[21][61]="6.748809750540721E-17";
+        results[21][62]="2.527470748254518E+32";
+        results[21][63]="5.740113004410473E-22";
+        results[21][64]="2.640933738459919E+27";
+        results[21][65]="0.000006227830168580984";
+        results[21][66]="5.552178009675986E+50";
+        results[21][67]="2.010351584774140E-10";
+        results[21][68]="1.184476752310447E+46";
+        results[21][69]="8.929030204524482E-16";
+        results[21][70]="8.696769366023154E+40";
+        results[21][71]="5.456790598951745E-21";
+        results[21][72]="2.119695083184782E+36";
+        results[21][73]="1.034002493473623E-25";
+        results[21][74]="5.920061938596140E+30";
+        results[22][0]="38681463.77870482";
+        results[22][1]="85.05593937424482";
+        results[22][2]="0.001908380599175486";
+        results[22][3]="2.225379927743381E-8";
+        results[22][4]="1.553244476779973E-13";
+        results[22][5]="484.6026400002877";
+        results[22][6]="301158352119.5565";
+        results[22][7]="0.004647309093335652";
+        results[22][8]="443964.1421858626";
+        results[22][9]="4.331956174545530E-8";
+        results[22][10]="15.80974722349805";
+        results[22][11]="5.249529284155089E-13";
+        results[22][12]="0.00007048689351547812";
+        results[22][13]="6.604795502245522E-18";
+        results[22][14]="5.310743606992122E-10";
+        results[22][15]="0.05705046547232572";
+        results[22][16]="655396082926770.0";
+        results[22][17]="6.752104736286019E-7";
+        results[22][18]="5143629387.040573";
+        results[22][19]="4.352044338016266E-12";
+        results[22][20]="174064.4640730606";
+        results[22][21]="8.114403856748394E-17";
+        results[22][22]="1";
+        results[22][23]="8.893451297674116E-22";
+        results[22][24]="0.000005296878350409827";
+        results[22][25]="0.000005302527864470423";
+        results[22][26]="1.420267787074702E+19";
+        results[22][27]="6.181574830231600E-11";
+        results[22][28]="219037186537017.3";
+        results[22][29]="1.055204897749860E-15";
+        results[22][30]="493648905.2304466";
+        results[22][31]="1.287493880047189E-20";
+        results[22][32]="10036.14140069709";
+        results[22][33]="5.539907864773438E-26";
+        results[22][34]="0.2655118394847626";
+        results[22][35]="6.517719108176616E-10";
+        results[22][36]="1.373401184015196E+23";
+        results[22][37]="5.514504270020602E-15";
+        results[22][38]="6.721514699722450E+17";
+        results[22][39]="5.877349344891688E-20";
+        results[22][40]="12186698189873.78";
+        results[22][41]="9.409536073813374E-25";
+        results[22][42]="44010712.35487979";
+        results[22][43]="1.697447998160085E-29";
+        results[22][44]="1156.126411647312";
+        results[22][45]="1.488918676420706E-13";
+        results[22][46]="8.106551296088482E+26";
+        results[22][47]="5.412601880645680E-19";
+        results[22][48]="6.712708910266456E+21";
+        results[22][49]="2.292272530980073E-23";
+        results[22][50]="2.262279861002728E+17";
+        results[22][51]="5.705661569067654E-29";
+        results[22][52]="4053740676394.876";
+        results[22][53]="1.188492358430754E-33";
+        results[22][54]="16531612.00830475";
+        results[22][55]="6.019353838720512E-18";
+        results[22][56]="6.948416117582402E+30";
+        results[22][57]="6.037482967145447E-23";
+        results[22][58]="5.553779556944628E+25";
+        results[22][59]="1.184646769690344E-27";
+        results[22][60]="2.868613412248970E+21";
+        results[22][61]="5.476256786824880E-33";
+        results[22][62]="2.050891838745521E+16";
+        results[22][63]="4.657759510115996E-38";
+        results[22][64]="214296029127.7612";
+        results[22][65]="5.053512913910754E-22";
+        results[22][66]="4.505261465506844E+34";
+        results[22][67]="1.631280465291153E-26";
+        results[22][68]="9.611322727176706E+29";
+        results[22][69]="7.245375712861636E-32";
+        results[22][70]="7.056909888490957E+24";
+        results[22][71]="4.427860268160242E-37";
+        results[22][72]="1.720006195812521E+20";
+        results[22][73]="8.390313820929822E-42";
+        results[22][74]="480377734267339.0";
+        results[23][0]="4.349432237720928E+28";
+        results[23][1]="9.563884315247705E+22";
+        results[23][2]="2.145826783438484E+18";
+        results[23][3]="25022680771022.83";
+        results[23][4]="174650360.6745100";
+        results[23][5]="5.448982895167197E+23";
+        results[23][6]="3.386293375197521E+32";
+        results[23][7]="5.225540611608288E+18";
+        results[23][8]="4.992034333194938E+26";
+        results[23][9]="48709505787460.23";
+        results[23][10]="1.777684128953709E+22";
+        results[23][11]="590269076.4751797";
+        results[23][12]="7.925707484777299E+16";
+        results[23][13]="7426.583090383436";
+        results[23][14]="597152154909.8750";
+        results[23][15]="6.414884791379698E+19";
+        results[23][16]="7.369423421683034E+35";
+        results[23][17]="759222096156514.8";
+        results[23][18]="5.783614498890633E+30";
+        results[23][19]="4893538169.095777";
+        results[23][20]="1.957220636251567E+26";
+        results[23][21]="91240.21243440706";
+        results[23][22]="1.124422866364071E+21";
+        results[23][23]="1";
+        results[23][24]="5955931137549612";
+        results[23][25]="5962283580343192";
+        results[23][26]="1.596981576147093E+40";
+        results[23][27]="69507040892.53014";
+        results[23][28]="2.462904211262749E+35";
+        results[23][29]="1186496.515729304";
+        results[23][30]="5.550701169967046E+29";
+        results[23][31]="14.47687559028860";
+        results[23][32]="1.128486688100694E+25";
+        results[23][33]="0.00006229199080701412";
+        results[23][34]="2.985475836070540E+20";
+        results[23][35]="732867240177.1831";
+        results[23][36]="1.544283695998176E+44";
+        results[23][37]="6200634.697873477";
+        results[23][38]="7.557824824970159E+38";
+        results[23][39]="66.08625997006110";
+        results[23][40]="1.370300211017172E+34";
+        results[23][41]="0.001058029752327336";
+        results[23][42]="4.948665133679859E+28";
+        results[23][43]="1.908649343595118E-8";
+        results[23][44]="1.299974973663679E+24";
+        results[23][45]="167417420.5923969";
+        results[23][46]="9.115191644675190E+47";
+        results[23][47]="608.6053321123179";
+        results[23][48]="7.547923393949451E+42";
+        results[23][49]="0.02577483649772239";
+        results[23][50]="2.543759205826400E+38";
+        results[23][51]="6.415576335994377E-8";
+        results[23][52]="4.558118710848557E+33";
+        results[23][53]="1.336367984318503E-12";
+        results[23][54]="1.858852255999673E+28";
+        results[23][55]="6768.299096993695";
+        results[23][56]="7.812957967622318E+51";
+        results[23][57]="0.06788683903541942";
+        results[23][58]="6.244796728573862E+46";
+        results[23][59]="0.000001332043916404155";
+        results[23][60]="3.225534515491407E+42";
+        results[23][61]="6.157628353187331E-12";
+        results[23][62]="2.306069679924920E+37";
+        results[23][63]="5.237291299199141E-17";
+        results[23][64]="2.409593553222759E+32";
+        results[23][65]="0.5682285475867381";
+        results[23][66]="5.065819010764803E+55";
+        results[23][67]="0.00001834249056626394";
+        results[23][68]="1.080719105044218E+51";
+        results[23][69]="8.146866126940509E-11";
+        results[23][70]="7.934950844489962E+45";
+        results[23][71]="4.978787334584325E-16";
+        results[23][72]="1.934014296859477E+41";
+        results[23][73]="9.434260716223996E-21";
+        results[23][74]="5.401477089023595E+35";
+        results[24][0]="7302690607518.291";
+        results[24][1]="16057748.30899485";
+        results[24][2]="360.2840150232697";
+        results[24][3]="0.004201304580784266";
+        results[24][4]="2.932377098408908E-8";
+        results[24][5]="91488346.14311905";
+        results[24][6]="5.685581812469896E+16";
+        results[24][7]="877.3675334597941";
+        results[24][8]="83816186216.83326";
+        results[24][9]="0.008178319168327438";
+        results[24][10]="2984729.151326427";
+        results[24][11]="9.910609488981233E-8";
+        results[24][12]="13.30725171553627";
+        results[24][13]="1.246922255961287E-12";
+        results[24][14]="0.0001002617627905542";
+        results[24][15]="10770.58253903672";
+        results[24][16]="1.237325155628808E+20";
+        results[24][17]="0.1274732831227585";
+        results[24][18]="971068060613965.9";
+        results[24][19]="8.216243700744122E-7";
+        results[24][20]="32861706944.73151";
+        results[24][21]="1.531921883031460E-11";
+        results[24][22]="188790.4410571613";
+        results[24][23]="1.678998593008280E-16";
+        results[24][24]="1";
+        results[24][25]="1.001066574251259";
+        results[24][26]="2.681329819411114E+24";
+        results[24][27]="0.00001167022238627271";
+        results[24][28]="4.135212705424321E+19";
+        results[24][29]="1.992125980518727E-10";
+        results[24][30]="93196194545840.82";
+        results[24][31]="2.430665374725046E-15";
+        results[24][32]="1894727561.549639";
+        results[24][33]="1.045881649206614E-20";
+        results[24][34]="50126.09728222654";
+        results[24][35]="0.0001230483065119351";
+        results[24][36]="2.592850152786563E+28";
+        results[24][37]="1.041085693348789E-9";
+        results[24][38]="1.268957724732794E+23";
+        results[24][39]="1.109587375069120E-14";
+        results[24][40]="2.300732126296780E+18";
+        results[24][41]="1.776430465518496E-19";
+        results[24][42]="8308801796717.613";
+        results[24][43]="3.204619562442379E-24";
+        results[24][44]="218265615.1727291";
+        results[24][45]="2.810936136197098E-8";
+        results[24][46]="1.530439394641047E+32";
+        results[24][47]="1.021847496313918E-13";
+        results[24][48]="1.267295275857541E+27";
+        results[24][49]="4.327591421469434E-18";
+        results[24][50]="4.270968127534385E+22";
+        results[24][51]="1.077174364147177E-23";
+        results[24][52]="7.653074902279439E+17";
+        results[24][53]="2.243759965412078E-28";
+        results[24][54]="3121010322433.718";
+        results[24][55]="1.136396466091162E-12";
+        results[24][56]="1.311794543487070E+36";
+        results[24][57]="1.139819072242488E-17";
+        results[24][58]="1.048500492089822E+31";
+        results[24][59]="2.236499861467814E-22";
+        results[24][60]="5.415667913209714E+26";
+        results[24][61]="1.033864934126942E-27";
+        results[24][62]="3.871887747972994E+21";
+        results[24][63]="8.793404722529862E-33";
+        results[24][64]="4.045704185582832E+16";
+        results[24][65]="9.540549319052715E-17";
+        results[24][66]="8.505502991508699E+39";
+        results[24][67]="3.079701585302480E-21";
+        results[24][68]="1.814525856806408E+35";
+        results[24][69]="1.367857676455993E-26";
+        results[24][70]="1.332277130348850E+30";
+        results[24][71]="8.359376929654525E-32";
+        results[24][72]="3.247207283284959E+25";
+        results[24][73]="1.584011046861337E-36";
+        results[24][74]="9.069072432637074E+19";
+        results[25][0]="7294910044299.792";
+        results[25][1]="16040639.77563644";
+        results[25][2]="359.9001547851519";
+        results[25][3]="0.004196828351727361";
+        results[25][4]="2.929252832762058E-8";
+        results[25][5]="91390870.99331748";
+        results[25][6]="5.679524178222003E+16";
+        results[25][7]="876.4327528526417";
+        results[25][8]="83726885276.85887";
+        results[25][9]="0.008169605677269126";
+        results[25][10]="2981549.107819164";
+        results[25][11]="9.900050350191554E-8";
+        results[25][12]="13.29307366544463";
+        results[25][13]="1.245593737753071E-12";
+        results[25][14]="0.0001001549401102962";
+        results[25][15]="10759.10715238146";
+        results[25][16]="1.236006862534849E+20";
+        results[25][17]="0.1273374682578942";
+        results[25][18]="970033447915559.5";
+        results[25][19]="8.207489803452292E-7";
+        results[25][20]="32826694837.26416";
+        results[25][21]="1.530289715424023E-11";
+        results[25][22]="188589.2965693774";
+        results[25][23]="1.677209724302378E-16";
+        results[25][24]="0.9989345621173533";
+        results[25][25]="1";
+        results[25][26]="2.678473029045643E+24";
+        results[25][27]="0.00001165778848924346";
+        results[25][28]="4.130806893155160E+19";
+        results[25][29]="1.990003494032078E-10";
+        results[25][30]="93096899789653.17";
+        results[25][31]="2.428075651754777E-15";
+        results[25][32]="1892708847.028269";
+        results[25][33]="1.044767327276784E-20";
+        results[25][34]="50072.69103927282";
+        results[25][35]="0.0001229172061847818";
+        results[25][36]="2.590087632009758E+28";
+        results[25][37]="1.039976481212013E-9";
+        results[25][38]="1.267605729101387E+23";
+        results[25][39]="1.108405178645614E-14";
+        results[25][40]="2.298280839131601E+18";
+        results[25][41]="1.774537789204645E-19";
+        results[25][42]="8299949284523.987";
+        results[25][43]="3.201205239361082E-24";
+        results[25][44]="218033066.7178449";
+        results[25][45]="2.807941258351893E-8";
+        results[25][46]="1.528808806532901E+32";
+        results[25][47]="1.020758781281058E-13";
+        results[25][48]="1.265945051462143E+27";
+        results[25][49]="4.322980641628383E-18";
+        results[25][50]="4.266417676295733E+22";
+        results[25][51]="1.076026701773399E-23";
+        results[25][52]="7.644921026359818E+17";
+        results[25][53]="2.241369378545362E-28";
+        results[25][54]="3117685079804.065";
+        results[25][55]="1.135185706246483E-12";
+        results[25][56]="1.310396907886189E+36";
+        results[25][57]="1.138604665823557E-17";
+        results[25][58]="1.047383379945576E+31";
+        results[25][59]="2.234117009790872E-22";
+        results[25][60]="5.409897855455146E+26";
+        results[25][61]="1.032763415260583E-27";
+        results[25][62]="3.867762492088947E+21";
+        results[25][63]="8.784035896021034E-33";
+        results[25][64]="4.041393739081530E+16";
+        results[25][65]="9.530384456386937E-17";
+        results[25][66]="8.496440906410580E+39";
+        results[25][67]="3.076420354566251E-21";
+        results[25][68]="1.812592592219525E+35";
+        results[25][69]="1.366400309069427E-26";
+        results[25][70]="1.330857671823993E+30";
+        results[25][71]="8.350470532798348E-32";
+        results[25][72]="3.243747585632540E+25";
+        results[25][73]="1.582323381485480E-36";
+        results[25][74]="9.059409899306875E+19";
+        results[26][0]="2.723533134436308E-12";
+        results[26][1]="5.988725516997952E-18";
+        results[26][2]="1.343676605597132E-22";
+        results[26][3]="1.566873478364917E-27";
+        results[26][4]="1.093627899552070E-32";
+        results[26][5]="3.412051194925813E-17";
+        results[26][6]="2.120433589075808E-8";
+        results[26][7]="3.272135815251872E-22";
+        results[26][8]="3.125918550193178E-14";
+        results[26][9]="3.050098167380094E-27";
+        results[26][10]="1.113152559494507E-18";
+        results[26][11]="3.696154578685082E-32";
+        results[26][12]="4.962929819077190E-24";
+        results[26][13]="4.650387456755103E-37";
+        results[26][14]="3.739255128732137E-29";
+        results[26][15]="4.016880900314683E-21";
+        results[26][16]="0.00004614595141080237";
+        results[26][17]="4.754106794320244E-26";
+        results[26][18]="3.621591247686330E-10";
+        results[26][19]="3.064242094077263E-31";
+        results[26][20]="1.225574963096063E-14";
+        results[26][21]="5.713291486714258E-36";
+        results[26][22]="7.040925726124371E-20";
+        results[26][23]="6.261813003582785E-41";
+        results[26][24]="3.729492704555177E-25";
+        results[26][25]="3.733470485444113E-25";
+        results[26][26]="1";
+        results[26][27]="4.352400925014057E-30";
+        results[26][28]="0.00001542224561666388";
+        results[26][29]="7.429619310899423E-35";
+        results[26][30]="3.475745276510183E-11";
+        results[26][31]="9.065148782251936E-40";
+        results[26][32]="7.066372617918999E-16";
+        results[26][33]="3.900607980544203E-45";
+        results[26][34]="1.869449141218870E-20";
+        results[26][35]="4.589077614441313E-29";
+        results[26][36]="9670.015728822264";
+        results[26][37]="3.882721498161075E-34";
+        results[26][38]="0.04732568576779893";
+        results[26][39]="4.138198020386811E-39";
+        results[26][40]="8.580563680159561E-7";
+        results[26][41]="6.625184461300789E-44";
+        results[26][42]="3.098761568445328E-12";
+        results[26][43]="1.195160527900366E-48";
+        results[26][44]="8.140200194419411E-17";
+        results[26][45]="1.048336581291759E-32";
+        results[26][46]="57077625.57077626";
+        results[26][47]="3.810972782670732E-38";
+        results[26][48]="472.6368485827938";
+        results[26][49]="1.613972063466582E-42";
+        results[26][50]="0.01592854447302717";
+        results[26][51]="4.017313932620759E-48";
+        results[26][52]="2.854208701546549E-7";
+        results[26][53]="8.368086421777320E-53";
+        results[26][54]="1.163978522835795E-12";
+        results[26][55]="4.238182329769274E-37";
+        results[26][56]="489232817981.0316";
+        results[26][57]="4.250946914441208E-42";
+        results[26][58]="3910374.935971505";
+        results[26][59]="8.341009917082876E-47";
+        results[26][60]="201.9769397260919";
+        results[26][61]="3.855791729321848E-52";
+        results[26][62]="0.001444017710892185";
+        results[26][63]="3.279493876087616E-57";
+        results[26][64]="1.508842424491952E-8";
+        results[26][65]="3.558140908285596E-41";
+        results[26][66]="3172121135540393";
+        results[26][67]="1.148572459459261E-45";
+        results[26][68]="67672609451.86232";
+        results[26][69]="5.101415225212420E-51";
+        results[26][70]="496871.7838081744";
+        results[26][71]="3.117623527377340E-56";
+        results[26][72]="12.11043587318969";
+        results[26][73]="5.907557643204166E-61";
+        results[26][74]="0.00003382303947460244";
+        results[27][0]="6.257541943766386E+17";
+        results[27][1]="1375959067231.062";
+        results[27][2]="30872077.93461244";
+        results[27][3]="360.0021012218345";
+        results[27][4]="0.002512700273696726";
+        results[27][5]="7839468959112.017";
+        results[27][6]="4.871871010065461E+21";
+        results[27][7]="75180018.37666884";
+        results[27][8]="7182055614931850";
+        results[27][9]="700.7852033691596";
+        results[27][10]="255755978980.9374";
+        results[27][11]="0.008492219908884301";
+        results[27][12]="1140274.047492801";
+        results[27][13]="1.068464862698761E-7";
+        results[27][14]="8.591246976449121";
+        results[27][15]="922911507.8137501";
+        results[27][16]="1.060241283048926E+25";
+        results[27][17]="10922.95235716340";
+        results[27][18]="8.320904507836979E+19";
+        results[27][19]="0.07040348871507895";
+        results[27][20]="2815859531810263";
+        results[27][21]="0.000001312675827697515";
+        results[27][22]="16177107411.35740";
+        results[27][23]="1.438703169001500E-11";
+        results[27][24]="85688.17001947338";
+        results[27][25]="85779.56281525363";
+        results[27][26]="2.297582454439834E+29";
+        results[27][27]="1";
+        results[27][28]="3.543388093690857E+24";
+        results[27][29]="0.00001707016297188988";
+        results[27][30]="7.985811363411926E+18";
+        results[27][31]="2.082792678898868E-10";
+        results[27][32]="162355737434647.7";
+        results[27][33]="8.961968457746355E-16";
+        results[27][34]="4295213546.332090";
+        results[27][35]="10.54378420900297";
+        results[27][36]="2.221765847269926E+33";
+        results[27][37]="0.00008920872789651233";
+        results[27][38]="1.087346652644278E+28";
+        results[27][39]="9.507851164638391E-10";
+        results[27][40]="1.971455256073830E+23";
+        results[27][41]="1.522190757571212E-14";
+        results[27][42]="7.119660210152448E+17";
+        results[27][43]="2.745979859142930E-19";
+        results[27][44]="18702781142325.76";
+        results[27][45]="0.002408639735523385";
+        results[27][46]="1.311405510525019E+37";
+        results[27][47]="8.756024199812025E-9";
+        results[27][48]="1.085922130625564E+32";
+        results[27][49]="3.708233894976874E-13";
+        results[27][50]="3.659714430599182E+27";
+        results[27][51]="9.230110005566145E-19";
+        results[27][52]="6.557779833982852E+22";
+        results[27][53]="1.922636853991178E-23";
+        results[27][54]="2.674336631412318E+17";
+        results[27][55]="9.737573359594823E-8";
+        results[27][56]="1.124052738729375E+41";
+        results[27][57]="9.766901045375269E-13";
+        results[27][58]="8.984408843169418E+35";
+        results[27][59]="1.916415803779827E-17";
+        results[27][60]="4.640586729161206E+31";
+        results[27][61]="8.858999425264104E-23";
+        results[27][62]="3.317749756446258E+26";
+        results[27][63]="7.534907589141790E-28";
+        results[27][64]="3.466689881027168E+21";
+        results[27][65]="8.175122121301600E-12";
+        results[27][66]="7.288209864375369E+44";
+        results[27][67]="2.638939930506406E-16";
+        results[27][68]="1.554834001227581E+40";
+        results[27][69]="1.172092211426029E-21";
+        results[27][70]="1.141603892583884E+35";
+        results[27][71]="7.162997116051003E-27";
+        results[27][72]="2.782472497785938E+30";
+        results[27][73]="1.357310078961783E-31";
+        results[27][74]="7.771122205267246E+24";
+        results[28][0]="1.765977019256848E-7";
+        results[28][1]="3.883173479306462E-13";
+        results[28][2]="8.712587252178613E-18";
+        results[28][3]="1.015982702721253E-22";
+        results[28][4]="7.091236430383361E-28";
+        results[28][5]="2.212421770302413E-12";
+        results[28][6]="0.001374918829450271";
+        results[28][7]="2.121698679027844E-17";
+        results[28][8]="2.026889357030855E-9";
+        results[28][9]="1.977726359178481E-22";
+        results[28][10]="7.217837059291388E-14";
+        results[28][11]="2.396638382345144E-27";
+        results[28][12]="3.218033185591791E-19";
+        results[28][13]="3.015376341646586E-32";
+        results[28][14]="2.424585382489199E-24";
+        results[28][15]="2.604601820097072E-16";
+        results[28][16]="2.992168102999295";
+        results[28][17]="3.082629412401127E-21";
+        results[28][18]="0.00002348290474490412";
+        results[28][19]="1.986897479292069E-26";
+        results[28][20]="7.946799665619501E-10";
+        results[28][21]="3.704578197445509E-31";
+        results[28][22]="4.565434827802628E-15";
+        results[28][23]="4.060247229376789E-36";
+        results[28][24]="2.418255289959476E-20";
+        results[28][25]="2.420834538784717E-20";
+        results[28][26]="64841.40019917012";
+        results[28][27]="2.822157702060747E-25";
+        results[28][28]="1";
+        results[28][29]="4.817469190655120E-30";
+        results[28][30]="0.000002253721904645720";
+        results[28][31]="5.877969400550175E-35";
+        results[28][32]="4.581934948749433E-11";
+        results[28][33]="2.529208830865435E-40";
+        results[28][34]="1.212176999177676E-15";
+        results[28][35]="2.975622181430421E-24";
+        results[28][36]="627017359.8048342";
+        results[28][37]="2.517610985241837E-29";
+        results[28][38]="3068.663730570020";
+        results[28][39]="2.683265539433148E-34";
+        results[28][40]="0.05563757635196901";
+        results[28][41]="4.295862370485278E-39";
+        results[28][42]="2.009280389813716E-7";
+        results[28][43]="7.749588209183903E-44";
+        results[28][44]="5.278219785077115E-12";
+        results[28][45]="6.797561181096882E-28";
+        results[28][46]="3700993162053.089";
+        results[28][47]="2.471088113492979E-33";
+        results[28][48]="30646435.04783151";
+        results[28][49]="1.046522084775171E-37";
+        results[28][50]="1032.829126765834";
+        results[28][51]="2.604882604307646E-43";
+        results[28][52]="0.01850708886689335";
+        results[28][53]="5.425984405757048E-48";
+        results[28][54]="7.547399722243467E-8";
+        results[28][55]="2.748096765616207E-32";
+        results[28][56]="3.172254094127582E+16";
+        results[28][57]="2.756373501047097E-37";
+        results[28][58]="253554186152.1326";
+        results[28][59]="5.408427620988176E-42";
+        results[28][60]="13096467.57978319";
+        results[28][61]="2.500149346056082E-47";
+        results[28][62]="93.63213028664973";
+        results[28][63]="2.126469748701247E-52";
+        results[28][64]="0.0009783545548396877";
+        results[28][65]="2.307148385991850E-36";
+        results[28][66]="2.056847760298206E+20";
+        results[28][67]="7.447504650154305E-41";
+        results[28][68]="4387986751990347";
+        results[28][69]="3.307829062001381E-46";
+        results[28][70]="32217862181.58138";
+        results[28][71]="2.021510748090225E-51";
+        results[28][72]="785257.6190398789";
+        results[28][73]="3.830543093426676E-56";
+        results[28][74]="2.193133238525025";
+        results[29][0]="3.665777505505325E+22";
+        results[29][1]="8.060608850055552E+16";
+        results[29][2]="1808540315956.603";
+        results[29][3]="21089552.67824123";
+        results[29][4]="147.1983763619884";
+        results[29][5]="4.592498016581085E+17";
+        results[29][6]="2.854027239276019E+26";
+        results[29][7]="4404176954869.778";
+        results[29][8]="4.207373782405491E+20";
+        results[29][9]="41053222.77960500";
+        results[29][10]="1.498263252683064E+16";
+        results[29][11]="497.4890938574387";
+        results[29][12]="66799247867.20172";
+        results[29][13]="0.006259254023867518";
+        results[29][14]="503290.2726585955";
+        results[29][15]="54065770158934.34";
+        results[29][16]="6.211078856100365E+29";
+        results[29][17]="639885651.6572606";
+        results[29][18]="4.874531380596274E+24";
+        results[29][19]="4124.359493873326";
+        results[29][20]="1.649579758814986E+20";
+        results[29][21]="0.07689884565596421";
+        results[29][22]="947683243446292.2";
+        results[29][23]="8.428174771211442E-7";
+        results[29][24]="5019762855.256830";
+        results[29][25]="5025116805.065672";
+        results[29][26]="1.345963983017241E+34";
+        results[29][27]="58581.74884719846";
+        results[29][28]="2.075778713727511E+29";
+        results[29][29]="1";
+        results[29][30]="4.678227956325009E+23";
+        results[29][31]="0.00001220136376160371";
+        results[29][32]="9.511083034298228E+18";
+        results[29][33]="5.250077853682115E-11";
+        results[29][34]="251621121216311.1";
+        results[29][35]="617673.3184308691";
+        results[29][36]="1.301549288620499E+38";
+        results[29][37]="5.226003292611552";
+        results[29][38]="6.369866851504902E+32";
+        results[29][39]="0.00005569865490033896";
+        results[29][40]="1.154912966748064E+28";
+        results[29][41]="8.917259665756348E-10";
+        results[29][42]="4.170821463085429E+22";
+        results[29][43]="1.608643024477765E-14";
+        results[29][44]="1.095641627623847E+18";
+        results[29][45]="141.1023280498135";
+        results[29][46]="7.682442825440876E+41";
+        results[29][47]="0.0005129432105733799";
+        results[29][48]="6.361521752392140E+36";
+        results[29][49]="2.172348267022037E-8";
+        results[29][50]="2.143924716258292E+32";
+        results[29][51]="5.407159861780895E-14";
+        results[29][52]="3.841662112296063E+27";
+        results[29][53]="1.126314293048790E-18";
+        results[29][54]="1.566673168742592E+22";
+        results[29][55]="0.005704440769329544";
+        results[29][56]="6.584897523124984E+45";
+        results[29][57]="5.721621440556141E-8";
+        results[29][58]="5.263223823910997E+40";
+        results[29][59]="1.122669893038318E-12";
+        results[29][60]="2.718536862713640E+36";
+        results[29][61]="5.189756793682972E-18";
+        results[29][62]="1.943595829699885E+31";
+        results[29][63]="4.414080639739539E-23";
+        results[29][64]="2.030847559414579E+26";
+        results[29][65]="4.789129509052666E-7";
+        results[29][66]="4.269560798205122E+49";
+        results[29][67]="1.545937162317696E-11";
+        results[29][68]="9.108489495899883E+44";
+        results[29][69]="6.866321155551707E-17";
+        results[29][70]="6.687715251833322E+39";
+        results[29][71]="4.196208980457067E-22";
+        results[29][72]="1.630021050395328E+35";
+        results[29][73]="7.951359815351027E-27";
+        results[29][74]="4.552459292898528E+29";
+        results[30][0]="0.07835824888672127";
+        results[30][1]="1.723004720015306E-7";
+        results[30][2]="3.865866163087327E-12";
+        results[30][3]="4.508021600300163E-17";
+        results[30][4]="3.146455831913338E-22";
+        results[30][5]="9.816746980813501E-7";
+        results[30][6]="610.0658766354783";
+        results[30][7]="9.414199128358610E-12";
+        results[30][8]="0.0008993520242460782";
+        results[30][9]="8.775378874836710E-17";
+        results[30][10]="3.202629856156106E-8";
+        results[30][11]="1.063413537138199E-21";
+        results[30][12]="1.427875009316049E-13";
+        results[30][13]="1.337954046340334E-26";
+        results[30][14]="1.075813913638266E-18";
+        results[30][15]="1.155689091332903E-10";
+        results[30][16]="1327656.307919525";
+        results[30][17]="1.367794937807870E-15";
+        results[30][18]="10.41961064339727";
+        results[30][19]="8.816072094770739E-21";
+        results[30][20]="0.0003526078195024119";
+        results[30][21]="1.643760124001572E-25";
+        results[30][22]="2.025731221936322E-9";
+        results[30][23]="1.801574196446855E-30";
+        results[30][24]="1.073005185322375E-14";
+        results[30][25]="1.074149625024506E-14";
+        results[30][26]="28770807997.87632";
+        results[30][27]="1.252220913433587E-19";
+        results[30][28]="443710.4675331262";
+        results[30][29]="2.137561506912014E-24";
+        results[30][30]="1";
+        results[30][31]="2.608116550863527E-29";
+        results[30][32]="0.00002033052498315981";
+        results[30][33]="1.122236432832213E-34";
+        results[30][34]="5.378556230380286E-10";
+        results[30][35]="1.320314709324433E-18";
+        results[30][36]="278214165870389.4";
+        results[30][37]="1.117090347328190E-23";
+        results[30][38]="1361598218.593171";
+        results[30][39]="1.190593007017408E-28";
+        results[30][40]="24686.97501554217";
+        results[30][41]="1.906119100865986E-33";
+        results[30][42]="0.08915387411693861";
+        results[30][43]="3.438573407486192E-38";
+        results[30][44]="0.000002342001368579163";
+        results[30][45]="3.016149049749527E-22";
+        results[30][46]="1.642169406271479E+18";
+        results[30][47]="1.096447662153521E-27";
+        results[30][48]="13598144023296.90";
+        results[30][49]="4.643528035193328E-32";
+        results[30][50]="458277094.7190988";
+        results[30][51]="1.155813678226253E-37";
+        results[30][52]="8211.789053806363";
+        results[30][53]="2.407566077505911E-42";
+        results[30][54]="0.03348860259416035";
+        results[30][55]="1.219359300697839E-26";
+        results[30][56]="1.407562347239223E+22";
+        results[30][57]="1.223031774845527E-31";
+        results[30][58]="1.125046464825440E+17";
+        results[30][59]="2.399775948327737E-36";
+        results[30][60]="5811039752858.027";
+        results[30][61]="1.109342435241184E-41";
+        results[30][62]="41545556.30561193";
+        results[30][63]="9.435368863912798E-47";
+        results[30][64]="434.1061569410814";
+        results[30][65]="1.023705889016741E-30";
+        results[30][66]="9.126448813663803E+25";
+        results[30][67]="3.304535770275098E-35";
+        results[30][68]="1.946995653254801E+21";
+        results[30][69]="1.467718379620295E-40";
+        results[30][70]="1.429540269150730E+16";
+        results[30][71]="8.969654791583536E-46";
+        results[30][72]="348427025278.1341";
+        results[30][73]="1.699652066890138E-50";
+        results[30][74]="973116.1746283781";
+        results[31][0]="3.004399817208225E+27";
+        results[31][1]="6.606317955556214E+21";
+        results[31][2]="1.482244404226248E+17";
+        results[31][3]="1728458645303.865";
+        results[31][4]="12064092.11609646";
+        results[31][5]="3.763921891283291E+22";
+        results[31][6]="2.339105115657083E+31";
+        results[31][7]="3.609577618470172E+17";
+        results[31][8]="3.448281572954666E+25";
+        results[31][9]="3364642148346.955";
+        results[31][10]="1.227947368799811E+21";
+        results[31][11]="40773236.79365905";
+        results[31][12]="5474736199359228";
+        results[31][13]="512.9962638737704";
+        results[31][14]="41248690104.82190";
+        results[31][15]="4.431125177094802E+18";
+        results[31][16]="5.090479209910875E+34";
+        results[31][17]="52443781216564.26";
+        results[31][18]="3.995070941115503E+29";
+        results[31][19]="338024467.9576074";
+        results[31][20]="1.351963428879995E+25";
+        results[31][21]="6302.479555437567";
+        results[31][22]="7.767027210749525E+19";
+        results[31][23]="0.06907567822651053";
+        results[31][24]="411409982796631.8";
+        results[31][25]="411848782090993.5";
+        results[31][26]="1.103125854876022E+39";
+        results[31][27]="4801245991.169322";
+        results[31][28]="1.701267787999033E+34";
+        results[31][29]="81958.05153739330";
+        results[31][30]="3.834184479481592E+28";
+        results[31][31]="1";
+        results[31][32]="7.795098335014412E+23";
+        results[31][33]="0.000004302861513074059";
+        results[31][34]="2.062237682054311E+19";
+        results[31][35]="50623301665.22991";
+        results[31][36]="1.066724436752164E+43";
+        results[31][37]="428313.0471904447";
+        results[31][38]="5.220618757019720E+37";
+        results[31][39]="4.564953228885464";
+        results[31][40]="9.465441644994164E+32";
+        results[31][41]="0.00007308412272583773";
+        results[31][42]="3.418324004248217E+27";
+        results[31][43]="1.318412479054169E-9";
+        results[31][44]="8.979665298330876E+22";
+        results[31][45]="11564471.87435279";
+        results[31][46]="6.296380450205607E+46";
+        results[31][47]="42.03982608792905";
+        results[31][48]="5.213779276388035E+41";
+        results[31][49]="0.001780414312257591";
+        results[31][50]="1.757118923873884E+37";
+        results[31][51]="4.431602866227630E-9";
+        results[31][52]="3.148551413888119E+32";
+        results[31][53]="9.231052487699542E-14";
+        results[31][54]="1.284014803060566E+27";
+        results[31][55]="467.5248505647183";
+        results[31][56]="5.396853705687309E+50";
+        results[31][57]="0.004689329449025547";
+        results[31][58]="4.313635694129337E+45";
+        results[31][59]="9.201183695311428E-8";
+        results[31][60]="2.228059843005880E+41";
+        results[31][61]="4.253423547632060E-13";
+        results[31][62]="1.592933271784059E+36";
+        results[31][63]="3.617694485619832E-18";
+        results[31][64]="1.664443089390894E+31";
+        results[31][65]="0.03925077231221895";
+        results[31][66]="3.499248839413294E+54";
+        results[31][67]="0.000001267019976228053";
+        results[31][68]="7.465140515327681E+49";
+        results[31][69]="5.627503031390007E-12";
+        results[31][70]="5.481121112771666E+44";
+        results[31][71]="3.439131118819729E-17";
+        results[31][72]="1.335933492553362E+40";
+        results[31][73]="6.516779575388975E-22";
+        results[31][74]="3.731106933492626E+34";
+        results[32][0]="3854.216698861785";
+        results[32][1]="0.008474964229612891";
+        results[32][2]="1.901508281900985E-7";
+        results[32][3]="2.217366056230347E-12";
+        results[32][4]="1.547651049109460E-17";
+        results[32][5]="0.04828575252702482";
+        results[32][6]="30007384.32189076";
+        results[32][7]="4.630573551915940E-7";
+        results[32][8]="44.23653717702960";
+        results[32][9]="4.316356258436777E-12";
+        results[32][10]="0.001575281434595963";
+        results[32][11]="5.230625072490977E-17";
+        results[32][12]="7.023306139407549E-9";
+        results[32][13]="6.581010807387358E-22";
+        results[32][14]="5.291618954893612E-14";
+        results[32][15]="0.000005684501960919277";
+        results[32][16]="65303591964.26306";
+        results[32][17]="6.727789562447809E-11";
+        results[32][18]="512510.6534153962";
+        results[32][19]="4.336372081917841E-16";
+        results[32][20]="17.34376361626097";
+        results[32][21]="8.085182873354881E-21";
+        results[32][22]="0.00009963988749008084";
+        results[32][23]="8.861424866987624E-26";
+        results[32][24]="5.277803628834801E-10";
+        results[32][25]="5.283432798288516E-10";
+        results[32][26]="1415153225099094";
+        results[32][27]="6.159314205957922E-15";
+        results[32][28]="21824840622.69226";
+        results[32][29]="1.051404972907783E-19";
+        results[32][30]="49187.12137676328";
+        results[32][31]="1.282857453520695E-24";
+        results[32][32]="1";
+        results[32][33]="5.519957963514394E-30";
+        results[32][34]="0.00002645556981354615";
+        results[32][35]="6.494247986306681E-14";
+        results[32][36]="1.368455394540179E+19";
+        results[32][37]="5.494645850284232E-19";
+        results[32][38]="66973096844326.95";
+        results[32][39]="5.856184274649082E-24";
+        results[32][40]="1214281236.514595";
+        results[32][41]="9.375651157286216E-29";
+        results[32][42]="4385.222427398534";
+        results[32][43]="1.691335275569338E-33";
+        results[32][44]="0.1151963055808490";
+        results[32][45]="1.483556894004392E-17";
+        results[32][46]="8.077358590748254E+22";
+        results[32][47]="5.393110424161355E-23";
+        results[32][48]="6.688535605726128E+17";
+        results[32][49]="2.284017770834574E-27";
+        results[32][50]="22541331082138.75";
+        results[32][51]="5.685114767983791E-33";
+        results[32][52]="403914264.9099497";
+        results[32][53]="1.184212448768611E-37";
+        results[32][54]="1647.207960537155";
+        results[32][55]="5.997677392530980E-22";
+        results[32][56]="6.923394001901749E+26";
+        results[32][57]="6.015741235696518E-27";
+        results[32][58]="5.533779701986738E+21";
+        results[32][59]="1.180380708474336E-31";
+        results[32][60]="2.858283176490243E+17";
+        results[32][61]="5.456536101060227E-37";
+        results[32][62]="2043506320669.287";
+        results[32][63]="4.640986335438119E-42";
+        results[32][64]="21352432.23186122";
+        results[32][65]="5.035314581717381E-26";
+        results[32][66]="4.489037455364987E+30";
+        results[32][67]="1.625406020263772E-30";
+        results[32][68]="9.576711151667440E+25";
+        results[32][69]="7.219284208528977E-36";
+        results[32][70]="7.031497073168779E+20";
+        results[32][71]="4.411914989412857E-41";
+        results[32][72]="1.713812238330015E+16";
+        results[32][73]="8.360099251239178E-46";
+        results[32][74]="47864783395.13761";
+        results[33][0]="6.982329800946383E+32";
+        results[33][1]="1.535331298830604E+27";
+        results[33][2]="3.444787613364996E+22";
+        results[33][3]="4.016998083837972E+17";
+        results[33][4]="2803737019990.124";
+        results[33][5]="8.747485550828852E+27";
+        results[33][6]="5.436161746200319E+36";
+        results[33][7]="8.388784085898711E+22";
+        results[33][8]="8.013926459118452E+30";
+        results[33][9]="7.819545523655909E+17";
+        results[33][10]="2.853792447348690E+26";
+        results[33][11]="9475842220292.549";
+        results[33][12]="1.272347758049958E+21";
+        results[33][13]="119222118.1915926";
+        results[33][14]="9586339225533875";
+        results[33][15]="1.029808922186089E+24";
+        results[33][16]="1.183045095558775E+40";
+        results[33][17]="1.218811738588753E+19";
+        results[33][18]="9.284683992214605E+34";
+        results[33][19]="78558063495777.08";
+        results[33][20]="3.142010089732407E+30";
+        results[33][21]="1464718196.550773";
+        results[33][22]="1.805084171812118E+25";
+        results[33][23]="16053.42817021349";
+        results[33][24]="9.561311270339060E+19";
+        results[33][25]="9.571509118748273E+19";
+        results[33][26]="2.563702902183168E+44";
+        results[33][27]="1115826288292324";
+        results[33][28]="3.953805584562284E+39";
+        results[33][29]="19047336589.46896";
+        results[33][30]="8.910778252638594E+33";
+        results[33][31]="232403.4824178150";
+        results[33][32]="1.811607998846661E+29";
+        results[33][33]="1";
+        results[33][34]="4.792712188826647E+24";
+        results[33][35]="1.176503159848700E+16";
+        results[33][36]="2.479104738813852E+48";
+        results[33][37]="99541443732.04527";
+        results[33][38]="1.213289979507148E+43";
+        results[33][39]="1060911.027467431";
+        results[33][40]="2.199801600919255E+38";
+        results[33][41]="16.98500463093566";
+        results[33][42]="7.944304026196954E+32";
+        results[33][43]="0.0003064036513952934";
+        results[33][44]="2.086905486278503E+28";
+        results[33][45]="2687623535922.464";
+        results[33][46]="1.463300743255233E+52";
+        results[33][47]="9770201.983074019";
+        results[33][48]="1.211700460390415E+47";
+        results[33][49]="413.7744863151833";
+        results[33][50]="4.083605569305342E+42";
+        results[33][51]="0.001029919938804072";
+        results[33][52]="7.317343131591340E+37";
+        results[33][53]="2.145328744523008E-8";
+        results[33][54]="2.984095117073005E+32";
+        results[33][55]="108654403.3881091";
+        results[33][56]="1.254247595301220E+56";
+        results[33][57]="1089.816494157951";
+        results[33][58]="1.002503957197447E+51";
+        results[33][59]="0.02138387133156396";
+        results[33][60]="5.178088665498566E+46";
+        results[33][61]="9.885104446676278E-8";
+        results[33][62]="3.702032396218190E+41";
+        results[33][63]="8.407647967817748E-13";
+        results[33][64]="3.868223702607104E+36";
+        results[33][65]="9122.016172948436";
+        results[33][66]="8.132376161261471E+59";
+        results[33][67]="0.2944598547683367";
+        results[33][68]="1.734924652500475E+55";
+        results[33][69]="0.000001307851301811848";
+        results[33][70]="1.273831634161944E+50";
+        results[33][71]="7.992660485051813E-12";
+        results[33][72]="3.104755959479955E+45";
+        results[33][73]="1.514522267469688E-16";
+        results[33][74]="8.671222446169412E+39";
+        results[34][0]="145686398.9710135";
+        results[34][1]="320.3470682862941";
+        results[34][2]="0.007187553680765358";
+        results[34][3]="8.381471545908569E-8";
+        results[34][4]="5.850000812747606E-13";
+        results[34][5]="1825.163958566520";
+        results[34][6]="1134255830941.353";
+        results[34][7]="0.01750320852868166";
+        results[34][8]="1672106.761971122";
+        results[34][9]="1.631549155379241E-7";
+        results[34][10]="59.54441524783812";
+        results[34][11]="1.977135669106896E-12";
+        results[34][12]="0.0002654755194806417";
+        results[34][13]="2.487570993091087E-17";
+        results[34][14]="2.000190883125157E-9";
+        results[34][15]="0.2148697609230333";
+        results[34][16]="2468425077384854";
+        results[34][17]="0.000002543052222977617";
+        results[34][18]="19372504808.15474";
+        results[34][19]="1.639114981260948E-11";
+        results[34][20]="655580.7997520574";
+        results[34][21]="3.056136356290082E-16";
+        results[34][22]="3.766310391056549";
+        results[34][23]="3.349549803478537E-21";
+        results[34][24]="0.00001994968797131100";
+        results[34][25]="0.00001997096579482185";
+        results[34][26]="5.349169324542341E+19";
+        results[34][27]="2.328172951619490E-10";
+        results[34][28]="824962031682160.1";
+        results[34][29]="3.974229171089060E-15";
+        results[34][30]="1859235001.303121";
+        results[34][31]="4.849101578843441E-20";
+        results[34][32]="37799.22364355827";
+        results[34][33]="2.086501255659210E-25";
+        results[34][34]="1";
+        results[34][35]="2.454775320311342E-9";
+        results[34][36]="5.172655150445800E+23";
+        results[34][37]="2.076933473370431E-14";
+        results[34][38]="2.531531065720401E+18";
+        results[34][39]="2.213592190953497E-19";
+        results[34][40]="45898888025191.66";
+        results[34][41]="3.543923348982476E-24";
+        results[34][42]="165758003.2599846";
+        results[34][43]="6.393116033748466E-29";
+        results[34][44]="4354.330917562191";
+        results[34][45]="5.607729882441468E-13";
+        results[34][46]="3.053178838209099E+27";
+        results[34][47]="2.038553870572805E-18";
+        results[34][48]="2.528214532087444E+22";
+        results[34][49]="8.633409852563746E-23";
+        results[34][50]="8.520448147972540E+17";
+        results[34][51]="2.148929245543152E-28";
+        results[34][52]="15267645632154.63";
+        results[34][53]="4.476231119249052E-33";
+        results[34][54]="62263182.08779341";
+        results[34][55]="2.267075491021919E-17";
+        results[34][56]="2.616989182503541E+31";
+        results[34][57]="2.273903483498682E-22";
+        results[34][58]="2.091725765495799E+26";
+        results[34][59]="4.461747438416318E-27";
+        results[34][60]="1.080408850247748E+22";
+        results[34][61]="2.062528284031250E-32";
+        results[34][62]="7.724295243200328E+16";
+        results[34][63]="1.754256804199234E-37";
+        results[34][64]="807105361266.0442";
+        results[34][65]="1.903309819900053E-21";
+        results[34][66]="1.696821307196509E+35";
+        results[34][67]="6.143908567153631E-26";
+        results[34][68]="3.619922465916360E+30";
+        results[34][69]="2.728833383445953E-31";
+        results[34][70]="2.657851304177320E+25";
+        results[34][71]="1.667669613811836E-36";
+        results[34][72]="6.478077207970342E+20";
+        results[34][73]="3.160052612799337E-41";
+        results[34][74]="1809251652203281";
+        results[35][0]="5.934816020251334E+16";
+        results[35][1]="130499547406.9147";
+        results[35][2]="2927988.407449751";
+        results[35][3]="34.14353841900911";
+        results[35][4]="0.0002383110488501100";
+        results[35][5]="743515686940.7634";
+        results[35][6]="4.620609558668262E+20";
+        results[35][7]="7130269.065301548";
+        results[35][8]="681164890381514.3";
+        results[35][9]="66.46429682910084";
+        results[35][10]="24256564238.34587";
+        results[35][11]="0.0008054242898515592";
+        results[35][12]="108146.5653023476";
+        results[35][13]="1.013359948875315E-8";
+        results[35][14]="0.8148162752717714";
+        results[35][15]="87531335.00453358";
+        results[35][16]="1.005560491406513E+24";
+        results[35][17]="1035.961296309220";
+        results[35][18]="7.891762903049598E+18";
+        results[35][19]="0.006677250531641558";
+        results[35][20]="267063463742543.0";
+        results[35][21]="1.244975998822763E-7";
+        results[35][22]="1534279068.187334";
+        results[35][23]="1.364503616996488E-12";
+        results[35][24]="8126.889579768451";
+        results[35][25]="8135.557510937055";
+        results[35][26]="2.179087136929461E+28";
+        results[35][27]="0.09484260870458016";
+        results[35][28]="3.360641704583902E+23";
+        results[35][29]="0.000001618978787266365";
+        results[35][30]="7.573951823286671E+17";
+        results[35][31]="1.975374910575696E-11";
+        results[35][32]="15398241676457.85";
+        results[35][33]="8.499764676608273E-17";
+        results[35][34]="407369257.6773865";
+        results[35][35]="1";
+        results[35][36]="2.107180688858216E+32";
+        results[35][37]="0.000008460788472922284";
+        results[35][38]="1.031267931029763E+27";
+        results[35][39]="9.017494076291857E-11";
+        results[35][40]="1.869779594303981E+22";
+        results[35][41]="1.443685423940549E-15";
+        results[35][42]="6.752471474210576E+16";
+        results[35][43]="2.604358932913510E-20";
+        results[35][44]="1773820553569.003";
+        results[35][45]="0.0002284416759465479";
+        results[35][46]="1.243771196877546E+36";
+        results[35][47]="8.304441769906065E-10";
+        results[35][48]="1.029916877185643E+31";
+        results[35][49]="3.516985762863528E-14";
+        results[35][50]="3.470968637118237E+26";
+        results[35][51]="8.754077115581401E-20";
+        results[35][52]="6.219569467652223E+21";
+        results[35][53]="1.823478948240904E-24";
+        results[35][54]="2.536410626773635E+16";
+        results[35][55]="9.235368598761958E-9";
+        results[35][56]="1.066080940626218E+40";
+        results[35][57]="9.263183741028816E-14";
+        results[35][58]="8.521047723546869E+34";
+        results[35][59]="1.817578741931636E-18";
+        results[35][60]="4.401253513135038E+30";
+        results[35][61]="8.402106160044240E-24";
+        results[35][62]="3.146640419303486E+25";
+        results[35][63]="7.146302921021462E-29";
+        results[35][64]="3.287899118863873E+20";
+        results[35][65]="7.753499084627650E-13";
+        results[35][66]="6.912328363238143E+43";
+        results[35][67]="2.502839472239110E-17";
+        results[35][68]="1.474645127790042E+39";
+        results[35][69]="1.111642829739649E-22";
+        results[35][70]="1.082726912799589E+34";
+        results[35][71]="6.793573326296614E-28";
+        results[35][72]="2.638969503387675E+29";
+        results[35][73]="1.287308287097552E-32";
+        results[35][74]="7.370335025096355E+23";
+        results[36][0]="2.816472290028026E-16";
+        results[36][1]="6.193087669080073E-22";
+        results[36][2]="1.389528872835434E-26";
+        results[36][3]="1.620342223120407E-31";
+        results[36][4]="1.130947384389897E-36";
+        results[36][5]="3.528485672216559E-21";
+        results[36][6]="2.192792285493067E-12";
+        results[36][7]="3.383795752781463E-26";
+        results[36][8]="3.232588899391471E-18";
+        results[36][9]="3.154181185340816E-31";
+        results[36][10]="1.151138313225971E-22";
+        results[36][11]="3.822283936590086E-36";
+        results[36][12]="5.132287225019476E-28";
+        results[36][13]="4.809079516690182E-41";
+        results[36][14]="3.866855270552440E-33";
+        results[36][15]="4.153954877593472E-25";
+        results[36][16]="4.772065806807389E-9";
+        results[36][17]="4.916338222853396E-30";
+        results[36][18]="3.745176170594929E-14";
+        results[36][19]="3.168807766200464E-35";
+        results[36][20]="1.267397073040055E-18";
+        results[36][21]="5.908254595372923E-40";
+        results[36][22]="7.281193664595935E-24";
+        results[36][23]="6.475494124501726E-45";
+        results[36][24]="3.856759708713939E-29";
+        results[36][25]="3.860873229312546E-29";
+        results[36][26]="0.0001034124481327801";
+        results[36][27]="4.500924349110802E-34";
+        results[36][28]="1.594852174924249E-9";
+        results[36][29]="7.683151216346878E-39";
+        results[36][30]="3.594353281298647E-15";
+        results[36][31]="9.374492282605629E-44";
+        results[36][32]="7.307508918374459E-20";
+        results[36][33]="4.033714204743355E-49";
+        results[36][34]="1.933243123531666E-24";
+        results[36][35]="4.745677507807144E-33";
+        results[36][36]="1";
+        results[36][37]="4.015217355426124E-38";
+        results[36][38]="0.000004894065024810755";
+        results[36][39]="4.279411881464243E-43";
+        results[36][40]="8.873370965245172E-11";
+        results[36][41]="6.851265444743684E-48";
+        results[36][42]="3.204505199727048E-16";
+        results[36][43]="1.235944761018426E-52";
+        results[36][44]="8.417980303958437E-21";
+        results[36][45]="1.084110523385301E-36";
+        results[36][46]="5902.536993880142";
+        results[36][47]="3.941020252233737E-42";
+        results[36][48]="0.04887653358970880";
+        results[36][49]="1.669048023009940E-46";
+        results[36][50]="0.000001647209779147603";
+        results[36][51]="4.154402686902390E-52";
+        results[36][52]="2.951607093088121E-11";
+        results[36][53]="8.653643030626684E-57";
+        results[36][54]="1.203698686204266E-16";
+        results[36][55]="4.382808103545301E-41";
+        results[36][56]="50592763.41431727";
+        results[36][57]="4.396008273048529E-46";
+        results[36][58]="404.3814452458765";
+        results[36][59]="8.625642554253372E-51";
+        results[36][60]="0.02088692980344213";
+        results[36][61]="3.987368622192980E-56";
+        results[36][62]="1.493294066304539E-7";
+        results[36][63]="3.391404903626805E-61";
+        results[36][64]="1.560330889633121E-12";
+        results[36][65]="3.679560621272072E-45";
+        results[36][66]="328036812399.9663";
+        results[36][67]="1.187766898905705E-49";
+        results[36][68]="6998190.214950595";
+        results[36][69]="5.275498373810540E-55";
+        results[36][70]="51.38272757170476";
+        results[36][71]="3.224010813224441E-60";
+        results[36][72]="0.001252369821601588";
+        results[36][73]="6.109149983692593E-65";
+        results[36][74]="3.497723315360298E-9";
+        results[37][0]="7.014495208389838E+21";
+        results[37][1]="1.542404089460013E+16";
+        results[37][2]="346065667144.4297";
+        results[37][3]="4035503.136413506";
+        results[37][4]="28.16652958678678";
+        results[37][5]="8.787782478196851E+16";
+        results[37][6]="5.461204441472514E+25";
+        results[37][7]="842742858791.6008";
+        results[37][8]="8.050844109405394E+19";
+        results[37][9]="7855567.721827779";
+        results[37][10]="2866938975720293";
+        results[37][11]="95.19494458811030";
+        results[37][12]="12782090658.38928";
+        results[37][13]="0.001197713371653776";
+        results[37][14]="96305.00489162340";
+        results[37][15]="10345529294895.73";
+        results[37][16]="1.188495013939524E+29";
+        results[37][17]="122442642.2696522";
+        results[37][18]="9.327455624622005E+23";
+        results[37][19]="789.1995590022467";
+        results[37][20]="3.156484346550524E+19";
+        results[37][21]="0.01471465694724737";
+        results[37][22]="181339962947614.9";
+        results[37][23]="1.612738128796641E-7";
+        results[37][24]="960535723.8013413";
+        results[37][25]="961560206.4717620";
+        results[37][26]="2.575513078838174E+33";
+        results[37][27]="11209.66550672107";
+        results[37][28]="3.972019529077253E+28";
+        results[37][29]="0.1913508170601013";
+        results[37][30]="8.951827418361983E+22";
+        results[37][31]="0.000002334740925030381";
+        results[37][32]="1.819953509739433E+18";
+        results[37][33]="1.004606686931215E-11";
+        results[37][34]="48147907134319.92";
+        results[37][35]="118192.2941579709";
+        results[37][36]="2.490525198215260E+37";
+        results[37][37]="1";
+        results[37][38]="1.218879226599518E+32";
+        results[37][39]="0.00001065798312432847";
+        results[37][40]="2.209935398205477E+27";
+        results[37][41]="1.706324922979563E-10";
+        results[37][42]="7.980900947732038E+21";
+        results[37][43]="3.078151570918528E-15";
+        results[37][44]="2.096519206508824E+17";
+        results[37][45]="27.00004576141425";
+        results[37][46]="1.470041711665625E+41";
+        results[37][47]="0.00009815210244864781";
+        results[37][48]="1.217282385065843E+36";
+        results[37][49]="4.156806158337618E-9";
+        results[37][50]="4.102417461713700E+31";
+        results[37][51]="1.034664457526358E-14";
+        results[37][52]="7.351051840566861E+26";
+        results[37][53]="2.155211602413563E-19";
+        results[37][54]="2.997841909050329E+21";
+        results[37][55]="0.001091549402082161";
+        results[37][56]="1.260025521307003E+45";
+        results[37][57]="1.094836937559011E-8";
+        results[37][58]="1.007122179075560E+40";
+        results[37][59]="2.148238013216586E-13";
+        results[37][60]="5.201942498882593E+35";
+        results[37][61]="9.930642028144481E-19";
+        results[37][62]="3.719086500476785E+30";
+        results[37][63]="8.446379369833354E-24";
+        results[37][64]="3.886043398184922E+25";
+        results[37][65]="9.164038445638694E-8";
+        results[37][66]="8.169839472243282E+48";
+        results[37][67]="2.958163391330656E-12";
+        results[37][68]="1.742916907223793E+44";
+        results[37][69]="1.313876163311878E-17";
+        results[37][70]="1.279699777703607E+39";
+        results[37][71]="8.029480169653943E-23";
+        results[37][72]="3.119058598183105E+34";
+        results[37][73]="1.521499197406275E-27";
+        results[37][74]="8.711168053289843E+28";
+    }
+
+    private static void initResults2() {
+        results[38][0]="5.754873046740801E-11";
+        results[38][1]="1.265428153832008E-16";
+        results[38][2]="2.839212118742058E-21";
+        results[38][3]="3.310831006343367E-26";
+        results[38][4]="2.310854838782263E-31";
+        results[38][5]="7.209723725223695E-16";
+        results[38][6]="4.480513181530232E-7";
+        results[38][7]="6.914080086037084E-21";
+        results[38][8]="6.605120453046024E-13";
+        results[38][9]="6.444910660872926E-26";
+        results[38][10]="2.352110786003469E-17";
+        results[38][11]="7.810039133548062E-31";
+        results[38][12]="1.048675732545652E-22";
+        results[38][13]="9.826349859084964E-36";
+        results[38][14]="7.901111348029064E-28";
+        results[38][15]="8.487739448770601E-20";
+        results[38][16]="0.0009750720071382617";
+        results[38][17]="1.004551062956811E-24";
+        results[38][18]="7.652485513797906E-9";
+        results[38][19]="6.474797024837234E-30";
+        results[38][20]="2.589661286915703E-13";
+        results[38][21]="1.207228462519536E-34";
+        results[38][22]="1.487759894419769E-18";
+        results[38][23]="1.323132016365500E-39";
+        results[38][24]="7.880483175360085E-24";
+        results[38][25]="7.888888295802402E-24";
+        results[38][26]="21.13017452946058";
+        results[38][27]="9.196699116773269E-29";
+        results[38][28]="0.0003258747415163162";
+        results[38][29]="1.569891527267555E-33";
+        results[38][30]="7.344310431260839E-10";
+        results[38][31]="1.915481759045105E-38";
+        results[38][32]="1.493136867068297E-14";
+        results[38][33]="8.242052739990580E-44";
+        results[38][34]="3.950178662790491E-19";
+        results[38][35]="9.696801092238556E-28";
+        results[38][36]="204329.1200526434";
+        results[38][37]="8.204258290543218E-33";
+        results[38][38]="1";
+        results[38][39]="8.744084640824158E-38";
+        results[38][40]="0.00001813088081229221";
+        results[38][41]="1.399913039571560E-42";
+        results[38][42]="6.547737276643480E-11";
+        results[38][43]="2.525395054525697E-47";
+        results[38][44]="1.720038508128311E-15";
+        results[38][45]="2.215153492831292E-31";
+        results[38][46]="1206060190.037704";
+        results[38][47]="8.052652002485662E-37";
+        results[38][48]="9986.899099608667";
+        results[38][49]="3.410351138672251E-41";
+        results[38][50]="0.3365729247153389";
+        results[38][51]="8.488654453591028E-47";
+        results[38][52]="0.000006030992800718365";
+        results[38][53]="1.768191265697641E-51";
+        results[38][54]="2.459506933606407E-11";
+        results[38][55]="8.955353231570062E-36";
+        results[38][56]="10337574829479.02";
+        results[38][57]="8.982325021761465E-41";
+        results[38][58]="82626904.87270614";
+        results[38][59]="1.762469952999227E-45";
+        results[38][60]="4267.807987338662";
+        results[38][61]="8.147355218982128E-51";
+        results[38][62]="0.03051234625478403";
+        results[38][63]="6.929627797002850E-56";
+        results[38][64]="3.188210376696939E-7";
+        results[38][65]="7.518413839248804E-40";
+        results[38][66]="6.702747322255918E+16";
+        results[38][67]="2.426953652810597E-44";
+        results[38][68]="1429934048581.875";
+        results[38][69]="1.077937940559859E-49";
+        results[38][70]="10498987.51063113";
+        results[38][71]="6.587592925063573E-55";
+        results[38][72]="255.8956236283385";
+        results[38][73]="1.248277240437528E-59";
+        results[38][74]="0.0007146867272151842";
+        results[39][0]="6.581447096100371E+26";
+        results[39][1]="1.447181958788470E+21";
+        results[39][2]="3.247008961334176E+16";
+        results[39][3]="378636660364.1785";
+        results[39][4]="2642763.575267104";
+        results[39][5]="8.245258390527376E+21";
+        results[39][6]="5.124050561692560E+30";
+        results[39][7]="7.907151371518986E+16";
+        results[39][8]="7.553815778735954E+24";
+        results[39][9]="737059500863.3713";
+        results[39][10]="2.689945125899165E+20";
+        results[39][11]="8931797.271363033";
+        results[39][12]="1199297325702478";
+        results[39][13]="112.3771127878607";
+        results[39][14]="9035950213.862933";
+        results[39][15]="9.706835875242173E+17";
+        results[39][16]="1.115121876320673E+34";
+        results[39][17]="11488350172947.65";
+        results[39][18]="8.751614180482857E+28";
+        results[39][19]="74047739.59538163";
+        results[39][20]="2.961615072691725E+24";
+        results[39][21]="1380.623029291435";
+        results[39][22]="1.701447270390950E+19";
+        results[39][23]="0.01513173843478247";
+        results[39][24]="90123592108977.16";
+        results[39][25]="90219715611751.54";
+        results[39][26]="2.416510749542446E+38";
+        results[39][27]="1051762362.161496";
+        results[39][28]="3.726802231475215E+33";
+        results[39][29]="17953.75492979660";
+        results[39][30]="8.399175823358240E+27";
+        results[39][31]="0.2190602947851342";
+        results[39][32]="1.707596539147366E+23";
+        results[39][33]="9.425861114736121E-7";
+        results[39][34]="4.517543945478293E+18";
+        results[39][35]="11089555385.78204";
+        results[39][36]="2.336769695694354E+42";
+        results[39][37]="93826.38237785791";
+        results[39][38]="1.143630283873541E+37";
+        results[39][39]="1";
+        results[39][40]="2.073502437023907E+32";
+        results[39][41]="0.00001600982946843494";
+        results[39][42]="7.488190640417148E+26";
+        results[39][43]="2.888118263100058E-10";
+        results[39][44]="1.967088127324202E+22";
+        results[39][45]="2533316.617830116";
+        results[39][46]="1.379286957501396E+46";
+        results[39][47]="9.209256695537514";
+        results[39][48]="1.142132025230187E+41";
+        results[39][49]="0.0003900180840828200";
+        results[39][50]="3.849149894363509E+36";
+        results[39][51]="9.707882302464703E-10";
+        results[39][52]="6.897226008724825E+31";
+        results[39][53]="2.022157079132508E-14";
+        results[39][54]="2.812766612669237E+26";
+        results[39][55]="102.4161315840830";
+        results[39][56]="1.182236363680106E+50";
+        results[39][57]="0.001027245891448147";
+        results[39][58]="9.449463067516497E+44";
+        results[39][59]="2.015614012667092E-8";
+        results[39][60]="4.880794460077878E+40";
+        results[39][61]="9.317562161903105E-14";
+        results[39][62]="3.489484320900643E+35";
+        results[39][63]="7.924932204624348E-19";
+        results[39][64]="3.646133938150488E+30";
+        results[39][65]="0.008598285753258867";
+        results[39][66]="7.665464822884150E+53";
+        results[39][67]="2.775537694911710E-7";
+        results[39][68]="1.635315881900131E+49";
+        results[39][69]="1.232762472960531E-12";
+        results[39][70]="1.200696006716784E+44";
+        results[39][71]="7.533770766933783E-18";
+        results[39][72]="2.926499846920735E+39";
+        results[39][73]="1.427567654834451E-22";
+        results[39][74]="8.173373847257529E+33";
+        results[40][0]="0.000003174072515461667";
+        results[40][1]="6.979408043839129E-12";
+        results[40][2]="1.565953771433517E-16";
+        results[40][3]="1.826072897737389E-21";
+        results[40][4]="1.274540858056698E-26";
+        results[40][5]="3.976488401123740E-11";
+        results[40][6]="0.02471205468678926";
+        results[40][7]="3.813427575647367E-16";
+        results[40][8]="3.643022377913347E-8";
+        results[40][9]="3.554659438554945E-21";
+        results[40][10]="1.297295377072253E-12";
+        results[40][11]="4.307589473674706E-26";
+        results[40][12]="5.783920502277423E-18";
+        results[40][13]="5.419675944492992E-31";
+        results[40][14]="4.357819914999574E-23";
+        results[40][15]="4.681371818966545E-15";
+        results[40][16]="53.77962699292531";
+        results[40][17]="5.540553012050880E-20";
+        results[40][18]="0.0004220691533424975";
+        results[40][19]="3.571143118677119E-25";
+        results[40][20]="1.428315211889754E-8";
+        results[40][21]="6.658410449100025E-30";
+        results[40][22]="8.205668052327118E-14";
+        results[40][23]="7.297670918825164E-35";
+        results[40][24]="4.346442545702108E-19";
+        results[40][25]="4.351078349405929E-19";
+        results[40][26]="1165424.600614822";
+        results[40][27]="5.072395109750087E-24";
+        results[40][28]="17.97346443838419";
+        results[40][29]="8.658661118125126E-29";
+        results[40][30]="0.00004050719050715733";
+        results[40][31]="1.056474739906990E-33";
+        results[40][32]="8.235324486033761E-10";
+        results[40][33]="4.545864497880714E-39";
+        results[40][34]="2.178702018774722E-14";
+        results[40][35]="5.348223946000686E-23";
+        results[40][36]="11269674218.70173";
+        results[40][37]="4.525019151292953E-28";
+        results[40][38]="55154.51843475961";
+        results[40][39]="4.822757775174344E-33";
+        results[40][40]="1";
+        results[40][41]="7.721152954810994E-38";
+        results[40][42]="0.000003611372963305955";
+        results[40][43]="1.392869480898883E-42";
+        results[40][44]="9.486789560505935E-11";
+        results[40][45]="1.221757241561856E-26";
+        results[40][46]="66519668984864.25";
+        results[40][47]="4.441401433197993E-32";
+        results[40][48]="550822610.4954504";
+        results[40][49]="1.880962747469021E-36";
+        results[40][50]="18563.51758085312";
+        results[40][51]="4.681876485468906E-42";
+        results[40][52]="0.3326365036071236";
+        results[40][53]="9.752373776010145E-47";
+        results[40][54]="0.000001356529205100136";
+        results[40][55]="4.939281949004150E-31";
+        results[40][56]="5.701639615032074E+17";
+        results[40][57]="4.954158109997452E-36";
+        results[40][58]="4557247148008.799";
+        results[40][59]="9.720818151340577E-41";
+        results[40][60]="235388894.3136845";
+        results[40][61]="4.493634536198847E-46";
+        results[40][62]="1682.893763997254";
+        results[40][63]="3.822002840758163E-51";
+        results[40][64]="0.01758442079954232";
+        results[40][65]="4.146744946969999E-35";
+        results[40][66]="3.696868007488996E+21";
+        results[40][67]="1.338574599842493E-39";
+        results[40][68]="7.886732384299944E+16";
+        results[40][69]="5.945314801413554E-45";
+        results[40][70]="579066600201.4157";
+        results[40][71]="3.633355154261108E-50";
+        results[40][72]="14113799.89078350";
+        results[40][73]="6.884813006940251E-55";
+        results[40][74]="39.41820227126789";
+        results[41][0]="4.110878950382567E+31";
+        results[41][1]="9.039334001912643E+25";
+        results[41][2]="2.028134632999056E+21";
+        results[41][3]="2.365026192881695E+16";
+        results[41][4]="165071313250.2498";
+        results[41][5]="5.150122558634225E+26";
+        results[41][6]="3.200565360046566E+35";
+        results[41][7]="4.938935412840446E+21";
+        results[41][8]="4.718236252065705E+29";
+        results[41][9]="4.603793577667779E+16";
+        results[41][10]="1.680183496771577E+25";
+        results[41][11]="557894591505.3629";
+        results[41][12]="7.491006247549473E+19";
+        results[41][13]="7019257.326220990";
+        results[41][14]="564400153772921.7";
+        results[41][15]="6.063047638564933E+22";
+        results[41][16]="6.965232693572741E+38";
+        results[41][17]="7.175810457942816E+17";
+        results[41][18]="5.466400624527316E+33";
+        results[41][19]="4625142306567.008";
+        results[41][20]="1.849872966186717E+29";
+        results[41][21]="86235960.97719082";
+        results[41][22]="1.062751651256206E+24";
+        results[41][23]="945.1530051969814";
+        results[41][24]="5.629266213401292E+18";
+        results[41][25]="5.635270243797986E+18";
+        results[41][26]="1.509391935939637E+43";
+        results[41][27]="65694788581924.34";
+        results[41][28]="2.327821316787288E+38";
+        results[41][29]="1121420747.497299";
+        results[41][30]="5.246261891744755E+32";
+        results[41][31]="13682.86247002409";
+        results[41][32]="1.066592584583160E+28";
+        results[41][33]="0.05887546231095213";
+        results[41][34]="2.821731458405042E+23";
+        results[41][35]="692671674463882.5";
+        results[41][36]="1.459584376149378E+47";
+        results[41][37]="5860548518.823794";
+        results[41][38]="7.143300846072895E+41";
+        results[41][39]="62461.62721293222";
+        results[41][40]="1.295143362464938E+37";
+        results[41][41]="1";
+        results[41][42]="4.677245722811041E+31";
+        results[41][43]="0.00001803965662966171";
+        results[41][44]="1.228675253039092E+27";
+        results[41][45]="158235078195.2310";
+        results[41][46]="8.615250775911171E+50";
+        results[41][47]="575225.1586248642";
+        results[41][48]="7.133942478787923E+45";
+        results[41][49]="24.36116417428315";
+        results[41][50]="2.404241657884309E+41";
+        results[41][51]="0.00006063701254035724";
+        results[41][52]="4.308119597603104E+36";
+        results[41][53]="1.263072216427666E-9";
+        results[41][54]="1.756899795975280E+31";
+        results[41][55]="6397078.231595606";
+        results[41][56]="7.384440702575934E+54";
+        results[41][57]="64.16344992765041";
+        results[41][58]="5.902288394855864E+49";
+        results[41][59]="0.001258985310643743";
+        results[41][60]="3.048623640683292E+45";
+        results[41][61]="5.819900942901146E-9";
+        results[41][62]="2.179588688174679E+40";
+        results[41][63]="4.950041610530071E-14";
+        results[41][64]="2.277434588131763E+35";
+        results[41][65]="537.0629193903215";
+        results[41][66]="4.787974061808353E+58";
+        results[41][67]="0.01733646008150164";
+        results[41][68]="1.021444909906334E+54";
+        results[41][69]="7.700035002815314E-8";
+        results[41][70]="7.499742636760013E+48";
+        results[41][71]="4.705715811519044E-13";
+        results[41][72]="1.827939424770661E+44";
+        results[41][73]="8.916819867750936E-18";
+        results[41][74]="5.105222303193294E+38";
+        results[42][0]="0.8789101950179163";
+        results[42][1]="0.000001932619010762593";
+        results[42][2]="4.336172938504800E-11";
+        results[42][3]="5.056450597297903E-16";
+        results[42][4]="3.529241845156713E-21";
+        results[42][5]="0.00001101101559303791";
+        results[42][6]="6842.842026531408";
+        results[42][7]="1.055949527892695E-10";
+        results[42][8]="0.01008763817785915";
+        results[42][9]="9.842958549761383E-16";
+        results[42][10]="3.592249790463821E-7";
+        results[42][11]="1.192784438894235E-20";
+        results[42][12]="1.601584926576693E-12";
+        results[42][13]="1.500724516564931E-25";
+        results[42][14]="1.206693398681896E-17";
+        results[42][15]="1.296285890859935E-9";
+        results[42][16]="14891739.93917645";
+        results[42][17]="1.534195738946580E-14";
+        results[42][18]="116.8722138729541";
+        results[42][19]="9.888602354180532E-20";
+        results[42][20]="0.003955047640890110";
+        results[42][21]="1.843733814467261E-24";
+        results[42][22]="2.272174083292525E-8";
+        results[42][23]="2.020746954959940E-29";
+        results[42][24]="1.203542971015447E-13";
+        results[42][25]="1.204826638958615E-13";
+        results[42][26]="322709565712.6364";
+        results[42][27]="1.404561412318563E-18";
+        results[42][28]="4976906.185267212";
+        results[42][29]="2.397609221230570E-23";
+        results[42][30]="11.21656248710349";
+        results[42][31]="2.925410226640957E-28";
+        results[42][32]="0.0002280386038692306";
+        results[42][33]="1.258763507416664E-33";
+        results[42][34]="6.032891204846025E-9";
+        results[42][35]="1.480939243977938E-17";
+        results[42][36]="3120606576282596";
+        results[42][37]="1.252991368454678E-22";
+        results[42][38]="15272451501.17909";
+        results[42][39]="1.335436085991919E-27";
+        results[42][40]="276902.9978793913";
+        results[42][41]="2.138010400272485E-32";
+        results[42][42]="1";
+        results[42][43]="3.856897349156122E-37";
+        results[42][44]="0.00002626920469555007";
+        results[42][45]="3.383082428693337E-21";
+        results[42][46]="1.841949575985368E+19";
+        results[42][47]="1.229837371638349E-26";
+        results[42][48]="152524432145942.5";
+        results[42][49]="5.208442236736284E-31";
+        results[42][50]="5140293669.325014";
+        results[42][51]="1.296425634527369E-36";
+        results[42][52]="92108.04505293148";
+        results[42][53]="2.700461535017569E-41";
+        results[42][54]="0.3756270036031754";
+        results[42][55]="1.367701979050812E-25";
+        results[42][56]="1.578801102230280E+23";
+        results[42][57]="1.371821232626794E-30";
+        results[42][58]="1.261915397360943E+18";
+        results[42][59]="2.691723687946608E-35";
+        results[42][60]="65179890502974.45";
+        results[42][61]="1.244300874447829E-40";
+        results[42][62]="465998328.3633725";
+        results[42][63]="1.058324044509485E-45";
+        results[42][64]="4869.178835365991";
+        results[42][65]="1.148246107257210E-29";
+        results[42][66]="1.023673834038115E+27";
+        results[42][67]="3.706553195815928E-34";
+        results[42][68]="2.183859840685134E+22";
+        results[42][69]="1.646275491848131E-39";
+        results[42][70]="1.603452775675989E+17";
+        results[42][71]="1.006086934575439E-44";
+        results[42][72]="3908153501227.777";
+        results[42][73]="1.906425361460782E-49";
+        results[42][74]="10915018.37993031";
+        results[43][0]="2.278801107346606E+36";
+        results[43][1]="5.010812670929508E+30";
+        results[43][2]="1.124264543740979E+26";
+        results[43][3]="1.311015082733337E+21";
+        results[43][4]="9150468694555485";
+        results[43][5]="2.854889460681936E+31";
+        results[43][6]="1.774183082168003E+40";
+        results[43][7]="2.737821187083793E+26";
+        results[43][8]="2.615480077546344E+34";
+        results[43][9]="2.552040580472019E+21";
+        results[43][10]="9.313833025008547E+29";
+        results[43][11]="3.092600945563700E+16";
+        results[43][12]="4.152521525954315E+24";
+        results[43][13]="389101492911.9866";
+        results[43][14]="3.128663507069788E+19";
+        results[43][15]="3.360955124054725E+27";
+        results[43][16]="3.861067223485925E+43";
+        results[43][17]="3.977797696073652E+22";
+        results[43][18]="3.030213233404445E+38";
+        results[43][19]="2.563874912653335E+17";
+        results[43][20]="1.025447991701273E+34";
+        results[43][21]="4780354900735.599";
+        results[43][22]="5.891196673382220E+28";
+        results[43][23]="52393070.69974453";
+        results[43][24]="3.120495211724467E+23";
+        results[43][25]="3.123823451568468E+23";
+        results[43][26]="8.367076862526411E+47";
+        results[43][27]="3.641687307612366E+18";
+        results[43][28]="1.290391144673877E+43";
+        results[43][29]="62164195833605.98";
+        results[43][30]="2.908182788312382E+37";
+        results[43][31]="758487966.3133965";
+        results[43][32]="5.912488283338024E+32";
+        results[43][33]="3263.668678379727";
+        results[43][34]="1.564182465516227E+28";
+        results[43][35]="3.839716512812981E+19";
+        results[43][36]="8.090976486489524E+51";
+        results[43][37]="324870292108974.2";
+        results[43][38]="3.959776503909459E+46";
+        results[43][39]="3462462090.893108";
+        results[43][40]="7.179423583569754E+41";
+        results[43][41]="55433.42761611934";
+        results[43][42]="2.592757622182496E+36";
+        results[43][43]="1";
+        results[43][44]="6.810968070305965E+31";
+        results[43][45]="8771512753466319";
+        results[43][46]="4.775728802811879E+55";
+        results[43][47]="31886702193.60218";
+        results[43][48]="3.954588840154493E+50";
+        results[43][49]="1350422.830899525";
+        results[43][50]="1.332753559139886E+46";
+        results[43][51]="3.361317445513614";
+        results[43][52]="2.388138358753168E+41";
+        results[43][53]="0.00007001642228327445";
+        results[43][54]="9.739097766897050E+35";
+        results[43][55]="354611973105.8077";
+        results[43][56]="4.093448591717685E+59";
+        results[43][57]="3556799.957164907";
+        results[43][58]="3.271840765057037E+54";
+        results[43][59]="69.78987108732747";
+        results[43][60]="1.689956579146075E+50";
+        results[43][61]="0.0003226170576512954";
+        results[43][62]="1.208220717788436E+45";
+        results[43][63]="2.743977733140975E-9";
+        results[43][64]="1.262460053916486E+40";
+        results[43][65]="29771238.46732512";
+        results[43][66]="2.654138135831102E+63";
+        results[43][67]="961.0194050476638";
+        results[43][68]="5.662219247714633E+58";
+        results[43][69]="0.004268393329701480";
+        results[43][70]="4.157364405943601E+53";
+        results[43][71]="2.608539568198692E-8";
+        results[43][72]="1.013289477896753E+49";
+        results[43][73]="4.942898887049463E-13";
+        results[43][74]="2.829999710082635E+43";
+        results[44][0]="33457.81515672613";
+        results[44][1]="0.07356975717997179";
+        results[44][2]="0.000001650667764311622";
+        results[44][3]="1.924858653278701E-11";
+        results[44][4]="1.343490176447769E-16";
+        results[44][5]="0.4191605996698921";
+        results[44][6]="260489120.4677608";
+        results[44][7]="0.000004019724008133258";
+        results[44][8]="384.0100336028812";
+        results[44][9]="3.746957193351482E-11";
+        results[44][10]="0.01367475655276438";
+        results[44][11]="4.540618769080169E-16";
+        results[44][12]="6.096815435177592E-8";
+        results[44][13]="5.712866201918743E-21";
+        results[44][14]="4.593566545569257E-13";
+        results[44][15]="0.00004934621759141124";
+        results[44][16]="566889637953.1077";
+        results[44][17]="5.840282401874423E-10";
+        results[44][18]="4449019.878121849";
+        results[44][19]="3.764332597345680E-15";
+        results[44][20]="150.5583319604680";
+        results[44][21]="7.018612995084639E-20";
+        results[44][22]="0.0008649573177513917";
+        results[44][23]="7.692455779988837E-25";
+        results[44][24]="4.581573690425900E-9";
+        results[44][25]="4.586460278954353E-9";
+        results[44][26]="1.228471015596839E+16";
+        results[44][27]="5.346798384636640E-14";
+        results[44][28]="189457817354.8698";
+        results[44][29]="9.127071980358501E-19";
+        results[44][30]="426985.2329790381";
+        results[44][31]="1.113627253106948E-23";
+        results[44][32]="8.680833946520647";
+        results[44][33]="4.791783847304273E-29";
+        results[44][34]="0.0002296564085119783";
+        results[44][35]="5.637548837665439E-13";
+        results[44][36]="1.187933404322369E+20";
+        results[44][37]="4.769810822125617E-18";
+        results[44][38]="581382332589848.2";
+        results[44][39]="5.083656324845414E-23";
+        results[44][40]="10540973778.55897";
+        results[44][41]="8.138847083690577E-28";
+        results[44][42]="38067.38771080486";
+        results[44][43]="1.468220067511016E-32";
+        results[44][44]="1";
+        results[44][45]="1.287851104706806E-16";
+        results[44][46]="7.011820865278762E+23";
+        results[44][47]="4.681669604739426E-22";
+        results[44][48]="5.806206693869941E+18";
+        results[44][49]="1.982717899951718E-26";
+        results[44][50]="195677552057591.1";
+        results[44][51]="4.935153726777955E-32";
+        results[44][52]="3506312662.314225";
+        results[44][53]="1.027995162516290E-36";
+        results[44][54]="14299.13878080998";
+        results[44][55]="5.206484150936237E-21";
+        results[44][56]="6.010083367684613E+27";
+        results[44][57]="5.222165073231839E-26";
+        results[44][58]="4.803782268957339E+22";
+        results[44][59]="1.024668892394211E-30";
+        results[44][60]="2.481228162724536E+18";
+        results[44][61]="4.736728381649903E-36";
+        results[44][62]="17739339038395.46";
+        results[44][63]="4.028763172600968E-41";
+        results[44][64]="185356918.5591225";
+        results[44][65]="4.371072975238266E-25";
+        results[44][66]="3.896858872973504E+31";
+        results[44][67]="1.410987975758478E-29";
+        results[44][68]="8.313383926141755E+26";
+        results[44][69]="6.266940742697879E-35";
+        results[44][70]="6.103925848762411E+21";
+        results[44][71]="3.829910140925841E-40";
+        results[44][72]="1.487731945645773E+17";
+        results[44][73]="7.257263337643890E-45";
+        results[44][74]="415506236539.3683";
+        results[45][0]="2.597956785100805E+20";
+        results[45][1]="571259805664574.7";
+        results[45][2]="12817225207.78065";
+        results[45][3]="149462.8258067859";
+        results[45][4]="1.043203031420026";
+        results[45][5]="3254728734851059";
+        results[45][6]="2.022664883508130E+24";
+        results[45][7]="31212645572.47396";
+        results[45][8]="2.981789060858130E+18";
+        results[45][9]="290946.4595446784";
+        results[45][10]="106182745061026.3";
+        results[45][11]="3.525732712799818";
+        results[45][12]="473409962.7585133";
+        results[45][13]="0.00004435967932193017";
+        results[45][14]="3566.845987692836";
+        results[45][15]="383167102245.4531";
+        results[45][16]="4.401825924450844E+27";
+        results[45][17]="4534904.990592084";
+        results[45][18]="3.454607339203797E+22";
+        results[45][19]="29.22956375615078";
+        results[45][20]="1.169066295088082E+18";
+        results[45][21]="0.0005449863706629740";
+        results[45][22]="6716283540777.093";
+        results[45][23]="5.973094057127134E-9";
+        results[45][24]="35575336.88235604";
+        results[45][25]="35613280.62065461";
+        results[45][26]="9.538921161825726E+31";
+        results[45][27]="415.1720928836645";
+        results[45][28]="1.471115850756691E+27";
+        results[45][29]="0.007087055286904757";
+        results[45][30]="3.315486017121880E+21";
+        results[45][31]="8.647173955412170E-8";
+        results[45][32]="6.740557130241340E+16";
+        results[45][33]="3.720759200959941E-13";
+        results[45][34]="1783252797412.961";
+        results[45][35]="4377.484956965496";
+        results[45][36]="9.224151767085032E+35";
+        results[45][37]="0.03703697426428437";
+        results[45][38]="4.514359854683718E+30";
+        results[45][39]="3.947394466849308E-7";
+        results[45][40]="8.184932046906727E+25";
+        results[45][41]="6.319711225890107E-12";
+        results[45][42]="2.955884230069542E+20";
+        results[45][43]="1.140054205136760E-16";
+        results[45][44]="7764872789604521";
+        results[45][45]="1";
+        results[45][46]="5.444589704238428E+39";
+        results[45][47]="0.000003635256892375972";
+        results[45][48]="4.508445636805033E+34";
+        results[45][49]="1.539555227079692E-10";
+        results[45][50]="1.519411299508411E+30";
+        results[45][51]="3.832084088557348E-16";
+        results[45][52]="2.722607178344951E+25";
+        results[45][53]="7.982251665267820E-21";
+        results[45][54]="1.110309936338901E+20";
+        results[45][55]="0.00004042768711311199";
+        results[45][56]="4.666753280498896E+43";
+        results[45][57]="4.054944747996101E-10";
+        results[45][58]="3.730075822741150E+38";
+        results[45][59]="7.956423600906009E-15";
+        results[45][60]="1.926642104554017E+34";
+        results[45][61]="3.678009332242079E-20";
+        results[45][62]="1.377437110048061E+29";
+        results[45][63]="3.128283353469004E-25";
+        results[45][64]="1.439272893284671E+24";
+        results[45][65]="3.394082560680328E-9";
+        results[45][66]="3.025861342768090E+47";
+        results[45][67]="1.095614213942617E-13";
+        results[45][68]="6.455236863763371E+42";
+        results[45][69]="4.866199764703870E-19";
+        results[45][70]="4.739620773281892E+37";
+        results[45][71]="2.973876503990548E-24";
+        results[45][72]="1.155204930297025E+33";
+        results[45][73]="5.635172661746553E-29";
+        results[45][74]="3.226353070015521E+27";
+        results[46][0]="4.771630051532411E-20";
+        results[46][1]="1.049224710578041E-25";
+        results[46][2]="2.354121413006176E-30";
+        results[46][3]="2.745162334095334E-35";
+        results[46][4]="1.916036080015227E-40";
+        results[46][5]="5.977913693510024E-25";
+        results[46][6]="3.714999648060815E-16";
+        results[46][7]="5.732781948321280E-30";
+        results[46][8]="5.476609299938448E-22";
+        results[46][9]="5.343771989249925E-35";
+        results[46][10]="1.950243284234377E-26";
+        results[46][11]="6.475662821856263E-40";
+        results[46][12]="8.695053043023237E-32";
+        results[46][13]="8.147478824234940E-45";
+        results[46][14]="6.551174985538704E-37";
+        results[46][15]="7.037575337351325E-29";
+        results[46][16]="8.084770687172574E-13";
+        results[46][17]="8.329195103649068E-34";
+        results[46][18]="6.345027865946450E-18";
+        results[46][19]="5.368552148823365E-39";
+        results[46][20]="2.147207335344303E-22";
+        results[46][21]="1.000968668472338E-43";
+        results[46][22]="1.233570187216990E-27";
+        results[46][23]="1.097069638227704E-48";
+        results[46][24]="6.534071218380670E-33";
+        results[46][25]="6.541040290498085E-33";
+        results[46][26]="1.752E-8";
+        results[46][27]="7.625406420624627E-38";
+        results[46][28]="2.701977432039512E-13";
+        results[46][29]="1.301669303269579E-42";
+        results[46][30]="6.089505724445841E-19";
+        results[46][31]="1.588214066650539E-47";
+        results[46][32]="1.238028482659409E-23";
+        results[46][33]="6.833865181913444E-53";
+        results[46][34]="3.275274895415460E-28";
+        results[46][35]="8.040063980501181E-37";
+        results[46][36]="0.0001694186755689661";
+        results[46][37]="6.802528064778204E-42";
+        results[46][38]="8.291460146518372E-10";
+        results[46][39]="7.250122931717692E-47";
+        results[46][40]="1.503314756763955E-14";
+        results[46][41]="1.160732317619898E-51";
+        results[46][42]="5.429030267916215E-20";
+        results[46][43]="2.093921244881440E-56";
+        results[46][44]="1.426163074062281E-24";
+        results[46][45]="1.836685690423163E-40";
+        results[46][46]="1";
+        results[46][47]="6.676824315239122E-46";
+        results[46][48]="0.000008280597587170547";
+        results[46][49]="2.827679055193452E-50";
+        results[46][50]="2.790680991674361E-10";
+        results[46][51]="7.038334009951569E-56";
+        results[46][52]="5.000573645109554E-15";
+        results[46][53]="1.466088741095387E-60";
+        results[46][54]="2.039290372008313E-20";
+        results[46][55]="7.425295441755768E-45";
+        results[46][56]="8571.358971027673";
+        results[46][57]="7.447658994100996E-50";
+        results[46][58]="0.06850976887822076";
+        results[46][59]="1.461344937472920E-54";
+        results[46][60]="0.000003538635984001130";
+        results[46][61]="6.755347109771878E-60";
+        results[46][62]="2.529919029483109E-11";
+        results[46][63]="5.745673270905503E-65";
+        results[46][64]="2.643491927709899E-16";
+        results[46][65]="6.233862871316364E-49";
+        results[46][66]="55575562.29466768";
+        results[46][67]="2.012298948972625E-53";
+        results[46][68]="1185.624117596628";
+        results[46][69]="8.937679474572159E-59";
+        results[46][70]="0.008705193652319216";
+        results[46][71]="5.462076419965100E-64";
+        results[46][72]="2.121748364982833E-7";
+        results[46][73]="1.035004099089370E-68";
+        results[46][74]="5.925796515950347E-13";
+        results[47][0]="7.146556246270681E+25";
+        results[47][1]="1.571442741399231E+20";
+        results[47][2]="3525810028628656";
+        results[47][3]="41114790572.36538";
+        results[47][4]="286968.1737232600";
+        results[47][5]="8.953228977234115E+20";
+        results[47][6]="5.564021865277680E+29";
+        results[47][7]="8586090748616571";
+        results[47][8]="8.202416360482460E+23";
+        results[47][9]="80034635283.92306";
+        results[47][10]="2.920914482927399E+19";
+        results[47][11]="969871.6809241588";
+        results[47][12]="130227375058794.5";
+        results[47][13]="12.20262573876507";
+        results[47][14]="981181273.6462696";
+        results[47][15]="1.054030330150941E+17";
+        results[47][16]="1.210870663276248E+33";
+        results[47][17]="1247478548243.150";
+        results[47][18]="9.503062483559163E+27";
+        results[47][19]="8040577.219577623";
+        results[47][20]="3.215911088814389E+23";
+        results[47][21]="149.9168798238013";
+        results[47][22]="1.847540281090668E+18";
+        results[47][23]="0.001643100951037101";
+        results[47][24]="9786196116419.247";
+        results[47][25]="9796633821214.788";
+        results[47][26]="2.624001946556017E+37";
+        results[47][27]="114207084.9942909";
+        results[47][28]="4.046800251839102E+32";
+        results[47][29]="1949.533553397026";
+        results[47][30]="9.120362371295601E+26";
+        results[47][31]="0.02378696805044898";
+        results[47][32]="1.854217550450959E+22";
+        results[47][33]="1.023520293369992E-7";
+        results[47][34]="4.905438185545787E+17";
+        results[47][35]="1204174859.319065";
+        results[47][36]="2.537414009565692E+41";
+        results[47][37]="10188.26876910955";
+        results[47][38]="1.241826915768028E+36";
+        results[47][39]="0.1085863966072925";
+        results[47][40]="2.251541579928655E+31";
+        results[47][41]="0.000001738449692274594";
+        results[47][42]="8.131156387513517E+25";
+        results[47][43]="3.136103551657476E-11";
+        results[47][44]="2.135990115551220E+21";
+        results[47][45]="275083.7229955457";
+        results[47][46]="1.497718006025124E+45";
+        results[47][47]="1";
+        results[47][48]="1.240200010695352E+40";
+        results[47][49]="0.00004235065836223342";
+        results[47][50]="4.179653170302738E+35";
+        results[47][51]="1.054143957912348E-10";
+        results[47][52]="7.489449188735266E+30";
+        results[47][53]="2.195787505969266E-15";
+        results[47][54]="3.054281909670523E+25";
+        results[47][55]="11.12099868317389";
+        results[47][56]="1.283747866701312E+49";
+        results[47][57]="0.0001115449297820002";
+        results[47][58]="1.026083144375309E+44";
+        results[47][59]="2.188682625866851E-9";
+        results[47][60]="5.299878830006924E+39";
+        results[47][61]="1.011760500325512E-14";
+        results[47][62]="3.789105284242457E+34";
+        results[47][63]="8.605398314572440E-20";
+        results[47][64]="3.959205458913181E+29";
+        results[47][65]="0.0009336568669461997";
+        results[47][66]="8.323652034369472E+52";
+        results[47][67]="3.013856369381733E-8";
+        results[47][68]="1.775730589302118E+48";
+        results[47][69]="1.338612348114789E-13";
+        results[47][70]="1.303792527901410E+43";
+        results[47][71]="8.180650204466976E-19";
+        results[47][72]="3.177780730489156E+38";
+        results[47][73]="1.550144275515960E-23";
+        results[47][74]="8.875172141979778E+32";
+        results[48][0]="5.762422338848205E-15";
+        results[48][1]="1.267088153400481E-20";
+        results[48][2]="2.842936621692024E-25";
+        results[48][3]="3.315174183018531E-30";
+        results[48][4]="2.313886238094478E-35";
+        results[48][5]="7.219181503001472E-20";
+        results[48][6]="4.486390757373126E-11";
+        results[48][7]="6.923150035938593E-25";
+        results[48][8]="6.613785107035720E-17";
+        results[48][9]="6.453365150275192E-30";
+        results[48][10]="2.355196305223146E-21";
+        results[48][11]="7.820284410257130E-35";
+        results[48][12]="1.050051394418058E-26";
+        results[48][13]="9.839240149597593E-40";
+        results[48][14]="7.911476094054727E-32";
+        results[48][15]="8.498873738599392E-24";
+        results[48][16]="9.763511150087314E-8";
+        results[48][17]="1.005868841707006E-28";
+        results[48][18]="7.662524110309441E-13";
+        results[48][19]="6.483290719429564E-34";
+        results[48][20]="2.593058426931717E-17";
+        results[48][21]="1.208812115230884E-38";
+        results[48][22]="1.489711550683502E-22";
+        results[48][23]="1.324867712358631E-43";
+        results[48][24]="7.890820861170891E-28";
+        results[48][25]="7.899237007522711E-28";
+        results[48][26]="0.002115789327468880";
+        results[48][27]="9.208763426010420E-33";
+        results[48][28]="3.263022268134115E-8";
+        results[48][29]="1.571950924515769E-37";
+        results[48][30]="7.353944761040615E-14";
+        results[48][31]="1.917994504540616E-42";
+        results[48][32]="1.495095576891135E-18";
+        results[48][33]="8.252864735875365E-48";
+        results[48][34]="3.955360541236747E-23";
+        results[48][35]="9.709521439561277E-32";
+        results[48][36]="20.45971607549835";
+        results[48][37]="8.215020707343183E-37";
+        results[48][38]="0.0001001311808626548";
+        results[48][39]="8.755555206487259E-42";
+        results[48][40]="1.815466505814869E-9";
+        results[48][41]="1.401749457573287E-46";
+        results[48][42]="6.556326654887352E-15";
+        results[48][43]="2.528707889543666E-51";
+        results[48][44]="1.722294869481269E-19";
+        results[48][45]="2.218059350292316E-35";
+        results[48][46]="120764.2310199132";
+        results[48][47]="8.063215540849113E-41";
+        results[48][48]="1";
+        results[48][49]="3.414824866715520E-45";
+        results[48][50]="0.00003370144439814430";
+        results[48][51]="8.499789943731035E-51";
+        results[48][52]="6.038904309100998E-10";
+        results[48][53]="1.770510794253370E-55";
+        results[48][54]="2.462733336018967E-15";
+        results[48][55]="8.967100941193022E-40";
+        results[48][56]="1035113574.931792";
+        results[48][57]="8.994108113211472E-45";
+        results[48][58]="8273.529555930313";
+        results[48][59]="1.764781976287603E-49";
+        results[48][60]="0.4273406534672904";
+        results[48][61]="8.158042989841942E-55";
+        results[48][62]="0.000003055237261381728";
+        results[48][63]="6.938718142525727E-60";
+        results[48][64]="3.192392698572340E-11";
+        results[48][65]="7.528276559381090E-44";
+        results[48][66]="6711540044014.826";
+        results[48][67]="2.430137351548587E-48";
+        results[48][68]="143180984.8402199";
+        results[48][69]="1.079351988849169E-53";
+        results[48][70]="1051.276017301760";
+        results[48][71]="6.596234586290859E-59";
+        results[48][72]="0.02562313097149101";
+        results[48][73]="1.249914741289858E-63";
+        results[48][74]="7.156242594292246E-8";
+        results[49][0]="1.687472290311238E+30";
+        results[49][1]="3.710550915072856E+24";
+        results[49][2]="8.325277964917845E+19";
+        results[49][3]="970818215402995.0";
+        results[49][4]="6776002660.189255";
+        results[49][5]="2.114070789798686E+25";
+        results[49][6]="1.313798198291870E+34";
+        results[49][7]="2.027380702131727E+20";
+        results[49][8]="1.936786033011718E+28";
+        results[49][9]="1889808526690925";
+        results[49][10]="6.896975385705340E+23";
+        results[49][11]="22900982379.74620";
+        results[49][12]="3.074978762902205E+18";
+        results[49][13]="288133.0824752154";
+        results[49][14]="23168028823874.12";
+        results[49][15]="2.488816870650781E+21";
+        results[49][16]="2.859154284968690E+37";
+        results[49][17]="2.945594228012286E+16";
+        results[49][18]="2.243899587646931E+32";
+        results[49][19]="189857195390.0929";
+        results[49][20]="7.593532693891262E+27";
+        results[49][21]="3539894.906509671";
+        results[49][22]="4.362483022786321E+22";
+        results[49][23]="38.79753030008030";
+        results[49][24]="2.310754187742728E+17";
+        results[49][25]="2.313218778660363E+17";
+        results[49][26]="6.195894108923685E+41";
+        results[49][27]="2696701525096.859";
+        results[49][28]="9.555460076266186E+36";
+        results[49][29]="46033134.51994738";
+        results[49][30]="2.153534968284877E+31";
+        results[49][31]="561.6670193647148";
+        results[49][32]="4.378249647482396E+26";
+        results[49][33]="0.002416775400787454";
+        results[49][34]="1.158290892101044E+22";
+        results[49][35]="28433438956710.49";
+        results[49][36]="5.991439348740924E+45";
+        results[49][37]="240569312.5704755";
+        results[49][38]="2.932249376494788E+40";
+        results[49][39]="2563.983673607429";
+        results[49][40]="5.316426395714516E+35";
+        results[49][41]="0.04104894137430629";
+        results[49][42]="1.919959854688953E+30";
+        results[49][43]="7.405088074035996E-7";
+        results[49][44]="5.043581843006266E+25";
+        results[49][45]="6495382448.194808";
+        results[49][46]="3.536469240253245E+49";
+        results[49][47]="23612.38381341809";
+        results[49][48]="2.928407865794388E+44";
+        results[49][49]="1";
+        results[49][50]="9.869157486415798E+39";
+        results[49][51]="0.000002489085172882200";
+        results[49][52]="1.768437487955098E+35";
+        results[49][53]="5.184777736365438E-11";
+        results[49][54]="7.211887672551995E+29";
+        results[49][55]="262593.2892956190";
+        results[49][56]="3.031234734820807E+53";
+        results[49][57]="2.633841694453359";
+        results[49][58]="2.422826902946868E+48";
+        results[49][59]="0.00005168001420772782";
+        results[49][60]="1.251427730987327E+44";
+        results[49][61]="2.389007726094191E-10";
+        results[49][62]="8.946980828098355E+38";
+        results[49][63]="2.031939678710256E-15";
+        results[49][64]="9.348627889203813E+33";
+        results[49][65]="22.04586429236709";
+        results[49][66]="1.965412665648703E+57";
+        results[49][67]="0.0007116433335235624";
+        results[49][68]="4.192923222382870E+52";
+        results[49][69]="3.160782854106722E-9";
+        results[49][70]="3.078564958187471E+47";
+        results[49][71]="1.931646524711914E-14";
+        results[49][72]="7.503497828319405E+42";
+        results[49][73]="3.660260159965578E-19";
+        results[49][74]="2.095639710265825E+37";
+        results[50][0]="1.709844323220016E-10";
+        results[50][1]="3.759744355260485E-16";
+        results[50][2]="8.435652158126978E-21";
+        results[50][3]="9.836890501942623E-26";
+        results[50][4]="6.865836997247178E-31";
+        results[50][5]="2.142098545603874E-15";
+        results[50][6]="0.000001331216165209868";
+        results[50][7]="2.054259145142100E-20";
+        results[50][8]="1.962463397384800E-12";
+        results[50][9]="1.914863076500820E-25";
+        results[50][10]="6.988413545126361E-17";
+        results[50][11]="2.320459716168051E-30";
+        results[50][12]="3.115745966294182E-22";
+        results[50][13]="2.919530698256769E-35";
+        results[50][14]="2.347518403243974E-27";
+        results[50][15]="2.521812904573124E-19";
+        results[50][16]="0.002897060148147514";
+        results[50][17]="2.984646087638879E-24";
+        results[50][18]="2.273648577130825E-8";
+        results[50][19]="1.923742686763465E-29";
+        results[50][20]="7.694205614150171E-13";
+        results[50][21]="3.586825837344361E-34";
+        results[50][22]="4.420319595457841E-18";
+        results[50][23]="3.931189704235886E-39";
+        results[50][24]="2.341389516707296E-23";
+        results[50][25]="2.343886782477983E-23";
+        results[50][26]="62.78037530003851";
+        results[50][27]="2.732453635286172E-28";
+        results[50][28]="0.0009682143677835323";
+        results[50][29]="4.664342886746792E-33";
+        results[50][30]="2.182085929066454E-9";
+        results[50][31]="5.691134427004636E-38";
+        results[50][32]="4.436295249628704E-14";
+        results[50][33]="2.448816329168904E-43";
+        results[50][34]="1.173647186900553E-18";
+        results[50][35]="2.881040149156310E-27";
+        results[50][36]="607087.2166127371";
+        results[50][37]="2.437587128400801E-32";
+        results[50][38]="2.971124313834108";
+        results[50][39]="2.597976247857604E-37";
+        results[50][40]="0.00005386910081262968";
+        results[50][41]="4.159315669124470E-42";
+        results[50][42]="1.945414142323337E-10";
+        results[50][43]="7.503262648537709E-47";
+        results[50][44]="5.110448232230970E-15";
+        results[50][45]="6.581496401425599E-31";
+        results[50][46]="3583354754.568408";
+        results[50][47]="2.392543015543006E-36";
+        results[50][48]="29672.31873465527";
+        results[50][49]="1.013257718682096E-40";
+        results[50][50]="1";
+        results[50][51]="2.522084763880048E-46";
+        results[50][52]="0.00001791882934677280";
+        results[50][53]="5.253516061023365E-51";
+        results[50][54]="7.307500850481565E-11";
+        results[50][55]="2.660746772529066E-35";
+        results[50][56]="30714219921944.59";
+        results[50][57]="2.668760426691597E-40";
+        results[50][58]="245494806.0441551";
+        results[50][59]="5.236517329758060E-45";
+        results[50][60]="12680.18807795731";
+        results[50][61]="2.420680518456101E-50";
+        results[50][62]="0.09065597382971390";
+        results[50][63]="2.058878563349585E-55";
+        results[50][64]="9.472569367822474E-7";
+        results[50][65]="2.233814215925896E-39";
+        results[50][66]="1.991469553864102E+17";
+        results[50][67]="7.210781006414067E-44";
+        results[50][68]="4248511818920.849";
+        results[50][69]="3.202687624001662E-49";
+        results[50][70]="31193797.06347679";
+        results[50][71]="1.957255750929793E-54";
+        results[50][72]="760.2977091658982";
+        results[50][73]="3.708786859469685E-59";
+        results[50][74]="0.002123423112003558";
+        results[51][0]="6.779487936755711E+35";
+        results[51][1]="1.490728784815458E+30";
+        results[51][2]="3.344713975889266E+25";
+        results[51][3]="3.900301307403033E+20";
+        results[51][4]="2722286378148756";
+        results[51][5]="8.493364601705167E+30";
+        results[51][6]="5.278237211829022E+39";
+        results[51][7]="8.145083680620504E+25";
+        results[51][8]="7.781115946181321E+33";
+        results[51][9]="7.592381921196569E+20";
+        results[51][10]="2.770887658182901E+29";
+        results[51][11]="9200561969210697";
+        results[51][12]="1.235385111125618E+24";
+        results[51][13]="115758627151.1858";
+        results[51][14]="9.307848954420085E+18";
+        results[51][15]="9.998922084971854E+26";
+        results[51][16]="1.148676757275435E+43";
+        results[51][17]="1.183404352773304E+22";
+        results[51][18]="9.014957029568579E+37";
+        results[51][19]="7.627589343206385E+16";
+        results[51][20]="3.050732364091198E+33";
+        results[51][21]="1422167045577.915";
+        results[51][22]="1.752645136580379E+28";
+        results[51][23]="15587064.16428300";
+        results[51][24]="9.283548079903686E+22";
+        results[51][25]="9.293449673246033E+22";
+        results[51][26]="2.489225429658254E+47";
+        results[51][27]="1.083410706261310E+18";
+        results[51][28]="3.838944597143528E+42";
+        results[51][29]="18493997321370.88";
+        results[51][30]="8.651913529303709E+36";
+        results[51][31]="225651988.7241708";
+        results[51][32]="1.758979441596474E+32";
+        results[51][33]="970.9492576298560";
+        results[51][34]="4.653480341774795E+27";
+        results[51][35]="1.142324869654275E+19";
+        results[51][36]="2.407084905737968E+51";
+        results[51][37]="96649690895033.44";
+        results[51][38]="1.178043004892208E+46";
+        results[51][39]="1030090774.530830";
+        results[51][40]="2.135895731345520E+41";
+        results[51][41]="16491.57763724665";
+        results[51][42]="7.713516096621809E+35";
+        results[51][43]="0.2975023978573374";
+        results[51][44]="2.026279332645786E+31";
+        results[51][45]="2609546076992446";
+        results[51][46]="1.420790770352885E+55";
+        results[51][47]="9486370362.359466";
+        results[51][48]="1.176499662485828E+50";
+        results[51][49]="401754.0303139023";
+        results[51][50]="3.964973795970168E+45";
+        results[51][51]="1";
+        results[51][52]="7.104768881441538E+40";
+        results[51][53]="0.00002083005351866606";
+        results[51][54]="2.897404938618912E+35";
+        results[51][55]="105497912307.8994";
+        results[51][56]="1.217810771541752E+59";
+        results[51][57]="1058156.515955435";
+        results[51][58]="9.733804730118538E+53";
+        results[51][59]="20.76265399463438";
+        results[51][60]="5.027661345707404E+49";
+        results[51][61]="0.00009597934824093921";
+        results[51][62]="3.594485606829729E+44";
+        results[51][63]="8.163399552765810E-10";
+        results[51][64]="3.755848932392581E+39";
+        results[51][65]="8857014.831211825";
+        results[51][66]="7.896124596543564E+62";
+        results[51][67]="285.9055773891117";
+        results[51][68]="1.684523803389072E+58";
+        results[51][69]="0.001269857250584455";
+        results[51][70]="1.236825879534966E+53";
+        results[51][71]="7.760467764448543E-9";
+        results[51][72]="3.014560493978934E+48";
+        results[51][73]="1.470524271263579E-13";
+        results[51][74]="8.419316996851535E+42";
+        results[52][0]="0.000009542165339768479";
+        results[52][1]="2.098208695724657E-11";
+        results[52][2]="4.707702715884311E-16";
+        results[52][3]="5.489694840870986E-21";
+        results[52][4]="3.831632560574457E-26";
+        results[52][5]="1.195445586399130E-10";
+        results[52][6]="0.07429146957357580";
+        results[52][7]="1.146424861461206E-15";
+        results[52][8]="1.095196209197808E-7";
+        results[52][9]="1.068631794769388E-20";
+        results[52][10]="3.900039120795011E-12";
+        results[52][11]="1.294983992124446E-25";
+        results[52][12]="1.738811116505963E-17";
+        results[52][13]="1.629308835837862E-30";
+        results[52][14]="1.310084692372364E-22";
+        results[52][15]="1.407353603167891E-14";
+        results[52][16]="161.6768647148971";
+        results[52][17]="1.665647922572809E-19";
+        results[52][18]="0.001268859998122764";
+        results[52][19]="1.073587258148610E-24";
+        results[52][20]="4.293922033213574E-8";
+        results[52][21]="2.001707682980056E-29";
+        results[52][22]="2.466857354302527E-13";
+        results[52][23]="2.193887573879874E-34";
+        results[52][24]="1.306664331355432E-18";
+        results[52][25]="1.308057985886294E-18";
+        results[52][26]="3503598.035624204";
+        results[52][27]="1.524906333112822E-23";
+        results[52][28]="54.03334944745757";
+        results[52][29]="2.603039962310287E-28";
+        results[52][30]="0.0001217761432311118";
+        results[52][31]="3.176063746613903E-33";
+        results[52][32]="2.475772922312967E-9";
+        results[52][33]="1.366616245837476E-38";
+        results[52][34]="6.549798338873787E-14";
+        results[52][35]="1.607828331528359E-22";
+        results[52][36]="33879848111.95684";
+        results[52][37]="1.360349541383301E-27";
+        results[52][38]="165810.1796906287";
+        results[52][39]="1.449858245525120E-32";
+        results[52][40]="3.006284605435543";
+        results[52][41]="2.321198326426144E-37";
+        results[52][42]="0.00001085681494407283";
+        results[52][43]="4.187362077807307E-42";
+        results[52][44]="2.851998941075561E-10";
+        results[52][45]="3.672949986886802E-26";
+        results[52][46]="199977056827865.5";
+        results[52][47]="1.335211675518248E-31";
+        results[52][48]="1655929534.258291";
+        results[52][49]="5.654709351113861E-36";
+        results[52][50]="55807.21712605078";
+        results[52][51]="1.407505320281584E-41";
+        results[52][52]="1";
+        results[52][53]="2.931841114927259E-46";
+        results[52][54]="0.000004078112866116254";
+        results[52][55]="1.484888728519684E-30";
+        results[52][56]="1.714075140041236E+18";
+        results[52][57]="1.489360925897899E-35";
+        results[52][58]="13700381944223.89";
+        results[52][59]="2.922354596061357E-40";
+        results[52][60]="707646009.2657238";
+        results[52][61]="1.350914432862808E-45";
+        results[52][62]="5059.257615288420";
+        results[52][63]="1.149002830210218E-50";
+        results[52][64]="0.05286377354516463";
+        results[52][65]="1.246629549674354E-34";
+        results[52][66]="1.111383737924134E+22";
+        results[52][67]="4.024136212733528E-39";
+        results[52][68]="2.370976215411088E+17";
+        results[52][69]="1.787330836195764E-44";
+        results[52][70]="1740839005707.414";
+        results[52][71]="1.092289966633505E-49";
+        results[52][72]="42430099.33586029";
+        results[52][73]="2.069770735406687E-54";
+        results[52][74]="118.5023346620570";
+        results[53][0]="3.254666595398102E+40";
+        results[53][1]="7.156624842464271E+34";
+        results[53][2]="1.605715497990454E+30";
+        results[53][3]="1.872439407756647E+25";
+        results[53][4]="1.306903208726412E+20";
+        results[53][5]="4.077456927364187E+35";
+        results[53][6]="2.533952784662378E+44";
+        results[53][7]="3.910255762579582E+30";
+        results[53][8]="3.735523741793833E+38";
+        results[53][9]="3.644917145504665E+25";
+        results[53][10]="1.330235496370605E+34";
+        results[53][11]="4.416965112915320E+20";
+        results[53][12]="5.930782222996091E+28";
+        results[53][13]="5557288993398558";
+        results[53][14]="4.468470974440470E+23";
+        results[53][15]="4.800238307602860E+31";
+        results[53][16]="5.514516591357251E+47";
+        results[53][17]="5.681235296456829E+26";
+        results[53][18]="4.327860714083221E+42";
+        results[53][19]="3.661819369005083E+21";
+        results[53][20]="1.464582105541592E+38";
+        results[53][21]="6.827476675964822E+16";
+        results[53][22]="8.414021284245927E+32";
+        results[53][23]="748296885090.3456";
+        results[53][24]="4.456804718040974E+27";
+        results[53][25]="4.461558231196124E+27";
+        results[53][26]="1.195016338977540E+52";
+        results[53][27]="5.201190219172758E+22";
+        results[53][28]="1.842983549563809E+47";
+        results[53][29]="8.878516468907865E+17";
+        results[53][30]="4.153572395553678E+41";
+        results[53][31]="10833000910053.42";
+        results[53][32]="8.444430735716701E+36";
+        results[53][33]="46612902.68696511";
+        results[53][34]="2.234022268644081E+32";
+        results[53][35]="5.484022730093443E+23";
+        results[53][36]="1.155582679411242E+56";
+        results[53][37]="4.639915630001839E+18";
+        results[53][38]="5.655496774583657E+50";
+        results[53][39]="49452142482867.52";
+        results[53][40]="1.025391379542793E+46";
+        results[53][41]="791720367.9994558";
+        results[53][42]="3.703070704887838E+40";
+        results[53][43]="14282.36358541959";
+        results[53][44]="9.727672234879347E+35";
+        results[53][45]="1.252779343391509E+20";
+        results[53][46]="6.820869514711989E+59";
+        results[53][47]="455417474269022.8";
+        results[53][48]="5.648087564592924E+54";
+        results[53][49]="19287229864.95862";
+        results[53][50]="1.903487090139787E+50";
+        results[53][51]="48007.55788283925";
+        results[53][52]="3.410826033199997E+45";
+        results[53][53]="1";
+        results[53][54]="1.390973353007717E+40";
+        results[53][55]="5064697131640181";
+        results[53][56]="5.846412110513578E+63";
+        results[53][57]="50799510188.83404";
+        results[53][58]="4.672961940014202E+58";
+        results[53][59]="996764.3134487737";
+        results[53][60]="2.413657430693617E+54";
+        results[53][61]="4.607734116234075";
+        results[53][62]="1.725624758289108E+49";
+        results[53][63]="0.00003919048765501487";
+        results[53][64]="1.803091350210368E+44";
+        results[53][65]="425203652178.5674";
+        results[53][66]="3.790736586186758E+67";
+        results[53][67]="13725628.55553436";
+        results[53][68]="8.086987399622141E+62";
+        results[53][69]="60.96274546037631";
+        results[53][70]="5.937699000276846E+57";
+        results[53][71]="0.0003725611053996715";
+        results[53][72]="1.447216874060142E+53";
+        results[53][73]="7.059627907080629E-9";
+        results[53][74]="4.041908480603224E+47";
+        results[54][0]="2.339848271255880";
+        results[54][1]="0.000005145048125465107";
+        results[54][2]="1.154382644727447E-10";
+        results[54][3]="1.346136073496915E-15";
+        results[54][4]="9.395602050179328E-21";
+        results[54][5]="0.00002931369546761954";
+        results[54][6]="18217.11953851009";
+        results[54][7]="2.811165112634539E-10";
+        results[54][8]="0.02685546587730432";
+        results[54][9]="2.620407599917871E-15";
+        results[54][10]="9.563342773563720E-7";
+        results[54][11]="3.175449122274317E-20";
+        results[54][12]="4.263764083022794E-12";
+        results[54][13]="3.995251944533639E-25";
+        results[54][14]="3.212477769454207E-17";
+        results[54][15]="3.450992283369952E-9";
+        results[54][16]="39645019.65068670";
+        results[54][17]="4.084359548780881E-14";
+        results[54][18]="311.1390095809556";
+        results[54][19]="2.632558963898978E-19";
+        results[54][20]="0.01052918880419032";
+        results[54][21]="4.908416585552623E-24";
+        results[54][22]="6.049016874444212E-8";
+        results[54][23]="5.379663697167850E-29";
+        results[54][24]="3.204090652350726E-13";
+        results[54][25]="3.207508052939222E-13";
+        results[54][26]="859122381024.4411";
+        results[54][27]="3.739245045871056E-18";
+        results[54][28]="13249596.37493202";
+        results[54][29]="6.382952232485079E-23";
+        results[54][30]="29.86090557789883";
+        results[54][31]="7.788072206149096E-28";
+        results[54][32]="0.0006070878868712484";
+        results[54][33]="3.351099615688073E-33";
+        results[54][34]="1.606085597408052E-8";
+        results[54][35]="3.942579286824783E-17";
+        results[54][36]="8307726937489580";
+        results[54][37]="3.335732938354928E-22";
+        results[54][38]="40658555840.44592";
+        results[54][39]="3.555218536425345E-27";
+        results[54][40]="737175.4299430523";
+        results[54][41]="5.691844249118863E-32";
+        results[54][42]="2.662215416909782";
+        results[54][43]="1.026789158436190E-36";
+        results[54][44]="0.00006993428173045223";
+        results[54][45]="9.006494198343990E-21";
+        results[54][46]="4.903666558358682E+19";
+        results[54][47]="3.274092011067419E-26";
+        results[54][48]="406052894714338.1";
+        results[54][49]="1.386599522072340E-30";
+        results[54][50]="13684569053.92081";
+        results[54][51]="3.451364311115807E-36";
+        results[54][52]="245211.4575613350";
+        results[54][53]="7.189210331295627E-41";
+        results[54][54]="1";
+        results[54][55]="3.641117294367092E-25";
+        results[54][56]="4.203108634591608E+23";
+        results[54][57]="3.652083634743231E-30";
+        results[54][58]="3.359490625690135E+18";
+        results[54][59]="7.165948300112717E-35";
+        results[54][60]="173522909369510.1";
+        results[54][61]="3.312596971229334E-40";
+        results[54][62]="1240587934.023157";
+        results[54][63]="2.817486587379466E-45";
+        results[54][64]="12962.80296320216";
+        results[54][65]="3.056878489146789E-29";
+        results[54][66]="2.725240262863416E+27";
+        results[54][67]="9.867643061497388E-34";
+        results[54][68]="5.813905336242105E+22";
+        results[54][69]="4.382739994878830E-39";
+        results[54][70]="4.268736699691402E+17";
+        results[54][71]="2.678420147978238E-44";
+        results[54][72]="10404346502618.53";
+        results[54][73]="5.075314988468698E-49";
+        results[54][74]="29058130.20690411";
+        results[55][0]="6.426182081186150E+24";
+        results[55][1]="1.413041028209840E+19";
+        results[55][2]="317040773861723.4";
+        results[55][3]="3697041222.976872";
+        results[55][4]="25804.17297930660";
+        results[55][5]="8.050741873371843E+19";
+        results[55][6]="5.003167452664180E+28";
+        results[55][7]="772061124475030.9";
+        results[55][8]="7.375611304488999E+22";
+        results[55][9]="7196712953.937829";
+        results[55][10]="2.626485773572434E+18";
+        results[55][11]="87210.84396777946";
+        results[55][12]="11710043204647.52";
+        results[55][13]="1.097259885232042";
+        results[55][14]="88227802.34034201";
+        results[55][15]="9477838818070297";
+        results[55][16]="1.088814680922766E+32";
+        results[55][17]="112173248444.9072";
+        results[55][18]="8.545152062590683E+26";
+        results[55][19]="723008.5578324046";
+        results[55][20]="2.891746668111807E+22";
+        results[55][21]="13.48052311620413";
+        results[55][22]="1.661307885852018E+17";
+        results[55][23]="0.0001477476077326687";
+        results[55][24]="879974577393.4671";
+        results[55][25]="880913135619.4773";
+        results[55][26]="2.359502074688797E+36";
+        results[55][27]="10269499.01244810";
+        results[55][28]="3.638882052887863E+31";
+        results[55][29]="175.3020217821514";
+        results[55][30]="8.201028191015562E+25";
+        results[55][31]="0.002138923735908606";
+        results[55][32]="1.667312085250398E+21";
+        results[55][33]="9.203492622641725E-9";
+        results[55][34]="4.410969127231112E+16";
+        results[55][35]="108279381.5218219";
+        results[55][36]="2.281642217442943E+40";
+        results[55][37]="916.1289430349850";
+        results[55][38]="1.116650537551916E+35";
+        results[55][39]="0.009764086814575751";
+        results[55][40]="2.024585780533582E+30";
+        results[55][41]="1.563213648163519E-7";
+        results[55][42]="7.311534349712662E+24";
+        results[55][43]="2.819983745167070E-12";
+        results[55][44]="1.920681924711475E+20";
+        results[55][45]="24735.52338530067";
+        results[55][46]="1.346747759525569E+44";
+        results[55][47]="0.08991998187294129";
+        results[55][48]="1.115187624805477E+39";
+        results[55][49]="0.000003808170432239159";
+        results[55][50]="3.758343373088038E+34";
+        results[55][51]="9.478860558694889E-12";
+        results[55][52]="6.734511352893900E+29";
+        results[55][53]="1.974451727335874E-16";
+        results[55][54]="2.746409739524259E+24";
+        results[55][55]="1";
+        results[55][56]="1.154345849032090E+48";
+        results[55][57]="0.00001003011806401597";
+        results[55][58]="9.226537774235836E+42";
+        results[55][59]="1.968063020435687E-10";
+        results[55][60]="4.765650083230079E+38";
+        results[55][61]="9.097748584902804E-16";
+        results[55][62]="3.407162784737478E+33";
+        results[55][63]="7.737972604557934E-21";
+        results[55][64]="3.560116830967234E+28";
+        results[55][65]="0.00008395440855134944";
+        results[55][66]="7.484626400471738E+51";
+        results[55][67]="2.710059101024540E-9";
+        results[55][68]="1.596736624012738E+47";
+        results[55][69]="1.203679980773772E-14";
+        results[55][70]="1.172370004749711E+42";
+        results[55][71]="7.356039180945439E-20";
+        results[55][72]="2.857459856817670E+37";
+        results[55][73]="1.393889451548389E-24";
+        results[55][74]="7.980553181260552E+31";
+        results[56][0]="5.566946930657264E-24";
+        results[56][1]="1.224105435467771E-29";
+        results[56][2]="2.746497283526938E-34";
+        results[56][3]="3.202715395976701E-39";
+        results[56][4]="2.235393578184839E-44";
+        results[56][5]="6.974289273983464E-29";
+        results[56][6]="4.334201449989442E-20";
+        results[56][7]="6.688299915682963E-34";
+        results[56][8]="6.389429399060419E-26";
+        results[56][9]="6.234451278160885E-39";
+        results[56][10]="2.275302307167926E-30";
+        results[56][11]="7.555001305796269E-44";
+        results[56][12]="1.014431092247293E-35";
+        results[56][13]="9.505469146461484E-49";
+        results[56][14]="7.643099545454276E-41";
+        results[56][15]="8.210571230465625E-33";
+        results[56][16]="9.432309059158727E-17";
+        results[56][17]="9.717473193927414E-38";
+        results[56][18]="7.402592619669160E-22";
+        results[56][19]="6.263361699083869E-43";
+        results[56][20]="2.505095566061517E-26";
+        results[56][21]="1.167806262525866E-47";
+        results[56][22]="1.439176904603599E-31";
+        results[56][23]="1.279924970982950E-52";
+        results[56][24]="7.623144988404633E-37";
+        results[56][25]="7.631275638562877E-37";
+        results[56][26]="2.044016597510373E-12";
+        results[56][27]="8.896379729748234E-42";
+        results[56][28]="3.152332601134258E-17";
+        results[56][29]="1.518626518466200E-46";
+        results[56][30]="7.104481033905097E-23";
+        results[56][31]="1.852931456982391E-51";
+        results[56][32]="1.444378291521926E-27";
+        results[56][33]="7.972907452613771E-57";
+        results[56][34]="3.821185072852883E-32";
+        results[56][35]="9.380150811181354E-41";
+        results[56][36]="1.976567264789908E-8";
+        results[56][37]="7.936347185751581E-46";
+        results[56][38]="9.673448719794147E-14";
+        results[56][39]="8.458545437455212E-51";
+        results[56][40]="1.753881457824083E-18";
+        results[56][41]="1.354198700046664E-55";
+        results[56][42]="6.333920077629528E-24";
+        results[56][43]="2.442927955717607E-60";
+        results[56][44]="1.663870430445044E-28";
+        results[56][45]="2.142817371937639E-44";
+        results[56][46]="0.0001166676140131492";
+        results[56][47]="7.789691620439270E-50";
+        results[56][48]="9.660775630982277E-10";
+        results[56][49]="3.298985685643760E-54";
+        results[56][50]="3.255820927704967E-14";
+        results[56][51]="8.211456355686501E-60";
+        results[56][52]="5.834049958719679E-19";
+        results[56][53]="1.710450753551403E-64";
+        results[56][54]="2.379191419821972E-24";
+        results[56][55]="8.662915025323579E-49";
+        results[56][56]="1";
+        results[56][57]="8.689006048253338E-54";
+        results[56][58]="0.000007992871271614319";
+        results[56][59]="1.704916271051602E-58";
+        results[56][60]="4.128442171144841E-10";
+        results[56][61]="7.881302291277083E-64";
+        results[56][62]="2.951596168162563E-15";
+        results[56][63]="6.703339914156715E-69";
+        results[56][64]="3.084098958689342E-20";
+        results[56][65]="7.272899072816394E-53";
+        results[56][66]="6483.868250358015";
+        results[56][67]="2.347701170578040E-57";
+        results[56][68]="0.1383239369164440";
+        results[56][69]="1.042737739112631E-62";
+        results[56][70]="0.000001015614172938495";
+        results[56][71]="6.372474234748120E-68";
+        results[56][72]="2.475393192788476E-11";
+        results[56][73]="1.207514587345858E-72";
+        results[56][74]="6.913485406433592E-17";
+        results[57][0]="6.406885781574903E+29";
+        results[57][1]="1.408798001370755E+24";
+        results[57][2]="3.160887756637065E+19";
+        results[57][3]="368593988563342.1";
+        results[57][4]="2572668917.216598";
+        results[57][5]="8.026567406274776E+24";
+        results[57][6]="4.988144128246639E+33";
+        results[57][7]="7.697428081578381E+19";
+        results[57][8]="7.353464094256007E+27";
+        results[57][9]="717510293299212.7";
+        results[57][10]="2.618599060159830E+23";
+        results[57][11]="8694897050.180986";
+        results[57][12]="1.167488072414467E+18";
+        results[57][13]="109396.5074218388";
+        results[57][14]="8796287518974.268";
+        results[57][15]="9.449379117552936E+20";
+        results[57][16]="1.085545228853283E+37";
+        results[57][17]="1.118364188028252E+16";
+        results[57][18]="8.519492999037822E+31";
+        results[57][19]="72083753473.07911";
+        results[57][20]="2.883063439189447E+27";
+        results[57][21]="1344004.430472940";
+        results[57][22]="1.656319372562645E+22";
+        results[57][23]="14.73039567328003";
+        results[57][24]="8.773322225891460E+16";
+        results[57][25]="8.782679625475591E+16";
+        results[57][26]="2.352417049958506E+41";
+        results[57][27]="1023866214425.824";
+        results[57][28]="3.627955353728795E+36";
+        results[57][29]="17477563.14166077";
+        results[57][30]="8.176402449775297E+30";
+        results[57][31]="213.2501055578004";
+        results[57][32]="1.662305542775258E+26";
+        results[57][33]="0.0009175856718636401";
+        results[57][34]="4.397724033833556E+21";
+        results[57][35]="10795424423794.65";
+        results[57][36]="2.274790987384843E+45";
+        results[57][37]="91337802.52514549";
+        results[57][38]="1.113297501011488E+40";
+        results[57][39]="973.4767579262472";
+        results[57][40]="2.018506429946206E+35";
+        results[57][41]="0.01558519688588414";
+        results[57][42]="7.289579547366953E+29";
+        results[57][43]="2.811516003270229E-7";
+        results[57][44]="1.914914572742777E+25";
+        results[57][45]="2466124847.925947";
+        results[57][46]="1.342703795638417E+49";
+        results[57][47]="8964.997350882443";
+        results[57][48]="1.111838981044821E+44";
+        results[57][49]="0.3796735400255500";
+        results[57][50]="3.747057959937145E+39";
+        results[57][51]="9.450397790132930E-7";
+        results[57][52]="6.714289213658032E+34";
+        results[57][53]="1.968522917411524E-11";
+        results[57][54]="2.738162922904441E+29";
+        results[57][55]="99699.72373382105";
+        results[57][56]="1.150879622417825E+53";
+        results[57][57]="1";
+        results[57][58]="9.198832671109769E+47";
+        results[57][59]="0.00001962153394281874";
+        results[57][60]="4.751339967101001E+43";
+        results[57][61]="9.070430205145709E-11";
+        results[57][62]="3.396931883544830E+38";
+        results[57][63]="7.714737309343017E-16";
+        results[57][64]="3.549426645075597E+33";
+        results[57][65]="8.370231338805882";
+        results[57][66]="7.462151843778957E+56";
+        results[57][67]="0.0002701921436744741";
+        results[57][68]="1.591942002897441E+52";
+        results[57][69]="1.200065615470761E-9";
+        results[57][70]="1.168849655873646E+47";
+        results[57][71]="7.333950741154235E-15";
+        results[57][72]="2.848879583052055E+42";
+        results[57][73]="1.389703932348617E-19";
+        results[57][74]="7.956589474147437E+36";
+        results[58][0]="6.964890014465238E-19";
+        results[58][1]="1.531496497153692E-24";
+        results[58][2]="3.436183556816159E-29";
+        results[58][3]="4.006964815448415E-34";
+        results[58][4]="2.796734117467348E-39";
+        results[58][5]="8.725636929437082E-24";
+        results[58][6]="5.422583828394453E-15";
+        results[58][7]="8.367831394252054E-29";
+        results[58][8]="7.993910050511732E-21";
+        results[58][9]="7.800014620905704E-34";
+        results[58][10]="2.846664521232035E-25";
+        results[58][11]="9.452174380221672E-39";
+        results[58][12]="1.269169811166505E-30";
+        results[58][13]="1.189243367426543E-43";
+        results[58][14]="9.562395396755339E-36";
+        results[58][15]="1.027236765294149E-27";
+        results[58][16]="1.180090200208327E-11";
+        results[58][17]="1.215767508784710E-32";
+        results[58][18]="9.261493608634160E-17";
+        results[58][19]="7.836184878051788E-38";
+        results[58][20]="3.134162281529605E-21";
+        results[58][21]="1.461059765435212E-42";
+        results[58][22]="1.800575607560021E-26";
+        results[58][23]="1.601333147361503E-47";
+        results[58][24]="9.537429953960697E-32";
+        results[58][25]="9.547602331172774E-32";
+        results[58][26]="2.557299533609959E-7";
+        results[58][27]="1.113039285562200E-36";
+        results[58][28]="3.943930152271277E-12";
+        results[58][29]="1.899976199866263E-41";
+        results[58][30]="8.888521774566507E-18";
+        results[58][31]="2.318230075295776E-46";
+        results[58][32]="1.807083140011844E-22";
+        results[58][33]="9.975022969440973E-52";
+        results[58][34]="4.780741416946553E-27";
+        results[58][35]="1.173564604311067E-35";
+        results[58][36]="0.002472912671331814";
+        results[58][37]="9.929281876384678E-41";
+        results[58][38]="1.210259541417636E-8";
+        results[58][39]="1.058261186752084E-45";
+        results[58][40]="2.194307149738259E-13";
+        results[58][41]="1.694258113296445E-50";
+        results[58][42]="7.924461513753702E-19";
+        results[58][43]="3.056383460588637E-55";
+        results[58][44]="2.081693016068045E-23";
+        results[58][45]="2.680910650403675E-39";
+        results[58][46]="14.59645852517100";
+        results[58][47]="9.745798919724109E-45";
+        results[58][48]="0.0001208673992447659";
+        results[58][49]="4.127410005162593E-49";
+        results[58][50]="4.073405935195787E-9";
+        results[58][51]="1.027347504625585E-54";
+        results[58][52]="7.299066581290476E-14";
+        results[58][53]="2.139970350361897E-59";
+        results[58][54]="2.976641733579987E-19";
+        results[58][55]="1.083830169527293E-43";
+        results[58][56]="125111.4857249578";
+        results[58][57]="1.087094456170119E-48";
+        results[58][58]="1";
+        results[58][59]="2.133046077079208E-53";
+        results[58][60]="0.00005165155337615015";
+        results[58][61]="9.860414391091898E-59";
+        results[58][62]="3.692785818589105E-10";
+        results[58][63]="8.386648159795576E-64";
+        results[58][64]="3.858562028444187E-15";
+        results[58][65]="9.099232085277269E-48";
+        results[58][66]="811206390.0471738";
+        results[58][67]="2.937243814892411E-52";
+        results[58][68]="17305.91325894164";
+        results[58][69]="1.304584677618646E-57";
+        results[58][70]="0.1270649980996593";
+        results[58][71]="7.972697192533506E-63";
+        results[58][72]="0.000003097001201032130";
+        results[58][73]="1.510739440573996E-67";
+        results[58][74]="8.649564307367203E-12";
+        results[59][0]="3.265231862221327E+34";
+        results[59][1]="7.179856607930284E+28";
+        results[59][2]="1.610927955912394E+24";
+        results[59][3]="1.878517702221967E+19";
+        results[59][4]="131114566512174.5";
+        results[59][5]="4.090693128103987E+29";
+        results[59][6]="2.542178477372429E+38";
+        results[59][7]="3.922949196535957E+24";
+        results[59][8]="3.747649962375796E+32";
+        results[59][9]="3.656749239841227E+19";
+        results[59][10]="1.334553693809554E+28";
+        results[59][11]="443130342180164.7";
+        results[59][12]="5.950034670157650E+22";
+        results[59][13]="5575329010.496484";
+        results[59][14]="4.482976481149991E+17";
+        results[59][15]="4.815820794179703E+25";
+        results[59][16]="5.532417761102616E+41";
+        results[59][17]="5.699677666829715E+20";
+        results[59][18]="4.341909773142817E+36";
+        results[59][19]="3673706331174018";
+        results[59][20]="1.469336417627336E+32";
+        results[59][21]="68496399638.76680";
+        results[59][22]="8.441334797725325E+26";
+        results[59][23]="750725.9991093196";
+        results[59][24]="4.471272353863239E+21";
+        results[59][25]="4.476041297826234E+21";
+        results[59][26]="1.198895589312202E+46";
+        results[59][27]="5.218074271917703E+16";
+        results[59][28]="1.848966224710778E+41";
+        results[59][29]="890733782210.6083";
+        results[59][30]="4.167055681580780E+35";
+        results[59][31]="10868166.89150073";
+        results[59][32]="8.471842964059609E+30";
+        results[59][33]="46.76421703510423";
+        results[59][34]="2.241274329850788E+26";
+        results[59][35]="5.501824910965054E+17";
+        results[59][36]="1.159333920586464E+50";
+        results[59][37]="4654977678672.980";
+        results[59][38]="5.673855592818941E+44";
+        results[59][39]="49612673.54342235";
+        results[59][40]="1.028719994995578E+40";
+        results[59][41]="794.2904429033256";
+        results[59][42]="3.715091576739267E+34";
+        results[59][43]="0.01432872685419792";
+        results[59][44]="9.759250109207765E+29";
+        results[59][45]="125684610342532.4";
+        results[59][46]="6.843011354521704E+53";
+        results[59][47]="456895846.0132791";
+        results[59][48]="5.666422331123308E+48";
+        results[59][49]="19349.83988163200";
+        results[59][50]="1.909666171287554E+44";
+        results[59][51]="0.04816339954701486";
+        results[59][52]="3.421898223260666E+39";
+        results[59][53]="0.000001003246190205216";
+        results[59][54]="1.395488717081967E+34";
+        results[59][55]="5081138101.861297";
+        results[59][56]="5.865390676242383E+57";
+        results[59][57]="50964.41506123880";
+        results[59][58]="4.688131263293223E+52";
+        results[59][59]="1";
+        results[59][60]="2.421492621803881E+48";
+        results[59][61]="0.000004622691697590433";
+        results[59][62]="1.731226464477344E+43";
+        results[59][63]="3.931770743217822E-11";
+        results[59][64]="1.808944527690531E+38";
+        results[59][65]="426583.9441094915";
+        results[59][66]="3.803042038163392E+61";
+        results[59][67]="13.77018455651177";
+        results[59][68]="8.113239298908500E+56";
+        results[59][69]="0.00006116064212757286";
+        results[59][70]="5.956973900613066E+51";
+        results[59][71]="3.737705096108644E-10";
+        results[59][72]="1.451914815301539E+47";
+        results[59][73]="7.082544802045064E-15";
+        results[59][74]="4.055029284323338E+41";
+        results[60][0]="1.348437667255375E-14";
+        results[60][1]="2.965054092372860E-20";
+        results[60][2]="6.652623846164517E-25";
+        results[60][3]="7.757685013397121E-30";
+        results[60][4]="5.414617634246651E-35";
+        results[60][5]="1.689327108110964E-19";
+        results[60][6]="1.049839447984212E-10";
+        results[60][7]="1.620054160484525E-24";
+        results[60][8]="1.547661111428041E-16";
+        results[60][9]="1.510121982992930E-29";
+        results[60][10]="5.511285402205287E-21";
+        results[60][11]="1.829988405457360E-34";
+        results[60][12]="2.457176460742298E-26";
+        results[60][13]="2.302434853732143E-39";
+        results[60][14]="1.851327747515669E-31";
+        results[60][15]="1.988781940038362E-23";
+        results[60][16]="2.284713862551959E-7";
+        results[60][17]="2.353786922788046E-28";
+        results[60][18]="1.793071650950697E-12";
+        results[60][19]="1.517124726334002E-33";
+        results[60][20]="6.067895497169673E-17";
+        results[60][21]="2.828685044174972E-38";
+        results[60][22]="3.486004756618662E-22";
+        results[60][23]="3.100261352644838E-43";
+        results[60][24]="1.846494312475907E-27";
+        results[60][25]="1.848463735764689E-27";
+        results[60][26]="0.004951060261414672";
+        results[60][27]="2.154899926158156E-32";
+        results[60][28]="7.635646741444116E-8";
+        results[60][29]="3.678449292763319E-37";
+        results[60][30]="1.720862431732932E-13";
+        results[60][31]="4.488209789961917E-42";
+        results[60][32]="3.498603666092752E-18";
+        results[60][33]="1.931214516782934E-47";
+        results[60][34]="9.255755353824531E-23";
+        results[60][35]="2.272079981340803E-31";
+        results[60][36]="47.87683060222675";
+        results[60][37]="1.922358811568574E-36";
+        results[60][38]="0.0002343123221491472";
+        results[60][39]="2.048846777260200E-41";
+        results[60][40]="4.248288785737604E-9";
+        results[60][41]="3.280168751088831E-46";
+        results[60][42]="1.534215526112867E-14";
+        results[60][43]="5.917311795698881E-51";
+        results[60][44]="4.030262170254993E-19";
+        results[60][45]="5.190377588220942E-35";
+        results[60][46]="282594.7637793763";
+        results[60][47]="1.886835590161396E-40";
+        results[60][48]="2.340053519098534";
+        results[60][49]="7.990872946462834E-45";
+        results[60][50]="0.00007886318356258115";
+        results[60][51]="1.988996336942614E-50";
+        results[60][52]="1.413135928001109E-9";
+        results[60][53]="4.143090014694539E-55";
+        results[60][54]="5.762927809552455E-15";
+        results[60][55]="2.098349611355051E-39";
+        results[60][56]="2422221163.685803";
+        results[60][57]="2.104669434147318E-44";
+        results[60][58]="19360.50195272046";
+        results[60][59]="4.129684274053472E-49";
+        results[60][60]="1";
+        results[60][61]="1.909025720733676E-54";
+        results[60][62]="0.000007149418705177280";
+        results[60][63]="1.623697180745017E-59";
+        results[60][64]="7.470369768638670E-11";
+        results[60][65]="1.761657005552672E-43";
+        results[60][66]="15705362898567.62";
+        results[60][67]="5.686651461384062E-48";
+        results[60][68]="335051167.4433505";
+        results[60][69]="2.525741419852499E-53";
+        results[60][70]="2460.042143830875";
+        results[60][71]="1.543554195644939E-58";
+        results[60][72]="0.05995949780016016";
+        results[60][73]="2.924867388928466E-63";
+        results[60][74]="1.674599066629639E-7";
+        results[61][0]="7.063486115509977E+39";
+        results[61][1]="1.553176607402299E+34";
+        results[61][2]="3.484826722820572E+29";
+        results[61][3]="4.063688052571492E+24";
+        results[61][4]="2.836325134564299E+19";
+        results[61][5]="8.849158446444201E+34";
+        results[61][6]="5.499346795499110E+43";
+        results[61][7]="8.486287758668364E+29";
+        results[61][8]="8.107073124364424E+37";
+        results[61][9]="7.910432879932915E+24";
+        results[61][10]="2.886962361139478E+33";
+        results[61][11]="9.585980878005454E+19";
+        results[61][12]="1.287136382739755E+28";
+        results[61][13]="1206078487432465";
+        results[61][14]="9.697762200941783E+22";
+        results[61][15]="1.041778493835083E+31";
+        results[61][16]="1.196795746509847E+47";
+        results[61][17]="1.232978108793337E+26";
+        results[61][18]="9.392600798807385E+41";
+        results[61][19]="7.947115169045187E+20";
+        results[61][20]="3.178529985880788E+37";
+        results[61][21]="1.481742762003150E+16";
+        results[61][22]="1.826064844887958E+32";
+        results[61][23]="162400187644.0589";
+        results[61][24]="9.672443343331502E+26";
+        results[61][25]="9.682759722348257E+26";
+        results[61][26]="2.593501076303929E+51";
+        results[61][27]="1.128795648353017E+22";
+        results[61][28]="3.999761060584132E+46";
+        results[61][29]="1.926872567934611E+17";
+        results[61][30]="9.014349115587456E+40";
+        results[61][31]="2351047312362.565";
+        results[61][32]="1.832664499013753E+36";
+        results[61][33]="10116230.99578109";
+        results[61][34]="4.848418359846594E+31";
+        results[61][35]="1.190177773229581E+23";
+        results[61][36]="2.507919620057646E+55";
+        results[61][37]="1.006984238446915E+18";
+        results[61][38]="1.227392169756080E+50";
+        results[61][39]="10732421019831.98";
+        results[61][40]="2.225370113978822E+45";
+        results[61][41]="171824230.3109566";
+        results[61][42]="8.036641462972210E+39";
+        results[61][43]="3099.650115465570";
+        results[61][44]="2.111161796555619E+35";
+        results[61][45]="2.718862051908959E+19";
+        results[61][46]="1.480308833506809E+59";
+        results[61][47]="98837620136215.22";
+        results[61][48]="1.225784175500373E+54";
+        results[61][49]="4185838283.725054";
+        results[61][50]="4.131069723475097E+49";
+        results[61][51]="10418.90800810271";
+        results[61][52]="7.402393339457015E+44";
+        results[61][53]="0.2170264114148377";
+        results[61][54]="3.018779551769291E+39";
+        results[61][55]="1099173043382890";
+        results[61][56]="1.268825839997009E+63";
+        results[61][57]="11024835397.91414";
+        results[61][58]="1.014156160519400E+58";
+        results[61][59]="216324.1819741618";
+        results[61][60]="5.238274105681931E+53";
+        results[61][61]="1";
+        results[61][62]="3.745061487400818E+48";
+        results[61][63]="0.000008505370897365375";
+        results[61][64]="3.913184451892906E+43";
+        results[61][65]="92280422752.79732";
+        results[61][66]="8.226899579190449E+66";
+        results[61][67]="2978823.909820644";
+        results[61][68]="1.755089854497003E+62";
+        results[61][69]="13.23052587726166";
+        results[61][70]="1.288637506091553E+57";
+        results[61][71]="0.00008085559973763583";
+        results[61][72]="3.140842847162717E+52";
+        results[61][73]="1.532125710597750E-9";
+        results[61][74]="8.772008928125169E+46";
+        results[62][0]="1.886080145619249E-9";
+        results[62][1]="4.147265973142270E-15";
+        results[62][2]="9.305125522088941E-20";
+        results[62][3]="1.085079127870824E-24";
+        results[62][4]="7.573507522122931E-30";
+        results[62][5]="2.362887358782933E-14";
+        results[62][6]="0.00001468426303279687";
+        results[62][7]="2.265994239939194E-19";
+        results[62][8]="2.164736988067710E-11";
+        results[62][9]="2.112230441755173E-24";
+        results[62][10]="7.708718190213518E-16";
+        results[62][11]="2.559632441351024E-29";
+        results[62][12]="3.436889853664501E-21";
+        results[62][13]="3.220450429158424E-34";
+        results[62][14]="2.589480101613048E-26";
+        results[62][15]="2.781739358191706E-18";
+        results[62][16]="0.03195663810957770";
+        results[62][17]="3.292277344287504E-23";
+        results[62][18]="2.507996418858833E-7";
+        results[62][19]="2.122025284706531E-28";
+        results[62][20]="8.487257142703900E-12";
+        results[62][21]="3.956524524331703E-33";
+        results[62][22]="4.875927540926171E-17";
+        results[62][23]="4.336382411621481E-38";
+        results[62][24]="2.582719502969886E-22";
+        results[62][25]="2.585474165089977E-22";
+        results[62][26]="692.5122818487806";
+        results[62][27]="3.014091096102228E-27";
+        results[62][28]="0.01068009450322826";
+        results[62][29]="5.145102622258724E-32";
+        results[62][30]="2.406996292561188E-8";
+        results[62][31]="6.277726868495983E-37";
+        results[62][32]="4.893549826028827E-13";
+        results[62][33]="2.701218933204230E-42";
+        results[62][34]="1.294616490585723E-17";
+        results[62][35]="3.177992610357912E-26";
+        results[62][36]="6696604.657880305";
+        results[62][37]="2.688832324474842E-31";
+        results[62][38]="32.77361864111679";
+        results[62][39]="2.865752953840177E-36";
+        results[62][40]="0.0005942145733696068";
+        results[62][41]="4.588021608964494E-41";
+        results[62][42]="2.145930444669381E-9";
+        results[62][43]="8.276633443518753E-46";
+        results[62][44]="5.637188611343273E-14";
+        results[62][45]="7.259859580559060E-30";
+        results[62][46]="39526956726.52857";
+        results[62][47]="2.639145457790906E-35";
+        results[62][48]="327306.8224978871";
+        results[62][49]="1.117695476511428E-39";
+        results[62][50]="11.03071267954583";
+        results[62][51]="2.782039238382100E-45";
+        results[62][52]="0.0001976574580780646";
+        results[62][53]="5.795002622652810E-50";
+        results[62][54]="8.060694228719894E-10";
+        results[62][55]="2.934993316079701E-34";
+        results[62][56]="338799735135353.3";
+        results[62][57]="2.943832947737714E-39";
+        results[62][58]="2707982669.793906";
+        results[62][59]="5.776251810602371E-44";
+        results[62][60]="139871.5114105495";
+        results[62][61]="2.670183128806329E-49";
+        results[62][62]="1";
+        results[62][63]="2.271089787438537E-54";
+        results[62][64]="0.00001044891910335168";
+        results[62][65]="2.464056279536351E-38";
+        results[62][66]="2.196732845873822E+18";
+        results[62][67]="7.954005347687989E-43";
+        results[62][68]="46864113190170.53";
+        results[62][69]="3.532792698269964E-48";
+        results[62][70]="344089812.7912729";
+        results[62][71]="2.158992582889526E-53";
+        results[62][72]="8386.625580725921";
+        results[62][73]="4.091056223648521E-58";
+        results[62][74]="0.02342287024561831";
+        results[63][0]="8.304736149364119E+44";
+        results[63][1]="1.826112730584637E+39";
+        results[63][2]="4.097207241015242E+34";
+        results[63][3]="4.777790529781906E+29";
+        results[63][4]="3.334745972621699E+24";
+        results[63][5]="1.040420053778644E+40";
+        results[63][6]="6.465734254108293E+48";
+        results[63][7]="9.977563425596263E+34";
+        results[63][8]="9.531710283058522E+42";
+        results[63][9]="9.300514904509633E+29";
+        results[63][10]="3.394281561588036E+38";
+        results[63][11]="1.127050306645041E+25";
+        results[63][12]="1.513321874227095E+33";
+        results[63][13]="1.418019862962190E+20";
+        results[63][14]="1.140192746202962E+28";
+        results[63][15]="1.224847812524888E+36";
+        results[63][16]="1.407105887505231E+52";
+        results[63][17]="1.449646492400778E+31";
+        results[63][18]="1.104314075441065E+47";
+        results[63][19]="9.343643287216183E+25";
+        results[63][20]="3.737085688838532E+42";
+        results[63][21]="1.742125981198698E+21";
+        results[63][22]="2.146954985177189E+37";
+        results[63][23]="1.909383959897199E+16";
+        results[63][24]="1.137215938028950E+32";
+        results[63][25]="1.138428863266573E+32";
+        results[63][26]="3.049251005746606E+56";
+        results[63][27]="1.327156289801157E+27";
+        results[63][28]="4.702629795748353E+51";
+        results[63][29]="2.265477415607447E+22";
+        results[63][30]="1.059841978011769E+46";
+        results[63][31]="2.764191404152434E+17";
+        results[63][32]="2.154714381216979E+41";
+        results[63][33]="1189393280769.765";
+        results[63][34]="5.700419674053768E+36";
+        results[63][35]="1.399324953128441E+28";
+        results[63][36]="2.948630518669679E+60";
+        results[63][37]="1.183939243330163E+23";
+        results[63][38]="1.443078949251087E+55";
+        results[63][39]="1.261840447564310E+18";
+        results[63][40]="2.616429243159934E+50";
+        results[63][41]="20201850381878.22";
+        results[63][42]="9.448901829150850E+44";
+        results[63][43]="364434444.1728835";
+        results[63][44]="2.482151362981211E+40";
+        results[63][45]="3.196641374864857E+24";
+        results[63][46]="1.740440071773177E+64";
+        results[63][47]="1.162061259043167E+19";
+        results[63][48]="1.441188385893991E+59";
+        results[63][49]="492140593777240.2";
+        results[63][50]="4.857013025445766E+54";
+        results[63][51]="1224979854.944370";
+        results[63][52]="8.703198753801531E+49";
+        results[63][53]="25516.39593777902";
+        results[63][54]="3.549262681424497E+44";
+        results[63][55]="1.292328173158645E+20";
+        results[63][56]="1.491793662272907E+68";
+        results[63][57]="1296220415423529";
+        results[63][58]="1.192371470635743E+63";
+        results[63][59]="25433832878.60738";
+        results[63][60]="6.158783865974074E+58";
+        results[63][61]="117572.7680858409";
+        results[63][62]="4.403172457253908E+53";
+        results[63][63]="1";
+        results[63][64]="4.600839280395232E+48";
+        results[63][65]="1.084966474317800E+16";
+        results[63][66]="9.672593562896609E+71";
+        results[63][67]="350228572717.9005";
+        results[63][68]="2.063507724325885E+67";
+        results[63][69]="1555549.550621002";
+        results[63][70]="1.515086786504186E+62";
+        results[63][71]="9.506416676394638";
+        results[63][72]="3.692775876635344E+57";
+        results[63][73]="0.0001801362608504635";
+        results[63][74]="1.031349371353387E+52";
+        results[64][0]="0.0001805048088671923";
+        results[64][1]="3.969086115148465E-10";
+        results[64][2]="8.905347462307516E-15";
+        results[64][3]="1.038460645678428E-19";
+        results[64][4]="7.248125329722949E-25";
+        results[64][5]="2.261370133514570E-9";
+        results[64][6]="1.405337995973826";
+        results[64][7]="2.168639854061398E-14";
+        results[64][8]="0.000002071732938743234";
+        results[64][9]="2.021482242194446E-19";
+        results[64][10]="7.377526913516641E-11";
+        results[64][11]="2.449662415828232E-24";
+        results[64][12]="3.289230033910451E-16";
+        results[64][13]="3.082089541802851E-29";
+        results[64][14]="2.478227724801148E-21";
+        results[64][15]="2.662226906608371E-13";
+        results[64][16]="3058.367836279547";
+        results[64][17]="3.150830542109802E-18";
+        results[64][18]="0.02400244842602282";
+        results[64][19]="2.030856267253379E-23";
+        results[64][20]="8.122617333673738E-7";
+        results[64][21]="3.786539531215795E-28";
+        results[64][22]="4.666442043141217E-12";
+        results[64][23]="4.150077504409531E-33";
+        results[64][24]="2.471757583175691E-17";
+        results[64][25]="2.474393896169260E-17";
+        results[64][26]="66275973.14124528";
+        results[64][27]="2.884596068061627E-22";
+        results[64][28]="1022.124336267703";
+        results[64][29]="4.924052498988474E-27";
+        results[64][30]="0.002303584005917990";
+        results[64][31]="6.008015572139217E-32";
+        results[64][32]="4.683307218312307E-8";
+        results[64][33]="2.585165897530746E-37";
+        results[64][34]="1.238995610723459E-12";
+        results[64][35]="3.041455847178024E-21";
+        results[64][36]="640889702718.8438";
+        results[64][37]="2.573311457270591E-26";
+        results[64][38]="3136555.878837656";
+        results[64][39]="2.742631008523106E-31";
+        results[64][40]="56.86852080029998";
+        results[64][41]="4.390905474129667E-36";
+        results[64][42]="0.0002053734384814057";
+        results[64][43]="7.921042704660115E-41";
+        results[64][44]="5.394996894497005E-9";
+        results[64][45]="6.947952710467755E-25";
+        results[64][46]="3782875179294822";
+        results[64][47]="2.525759297863022E-30";
+        results[64][48]="31324467082.23605";
+        results[64][49]="1.069675691290314E-34";
+        results[64][50]="1055679.785673480";
+        results[64][51]="2.662513902983238E-40";
+        results[64][52]="18.91654592432077";
+        results[64][53]="5.546030709333330E-45";
+        results[64][54]="0.00007714380931645150";
+        results[64][55]="2.808896582554887E-29";
+        results[64][56]="3.242438110432659E+19";
+        results[64][57]="2.817356435263650E-34";
+        results[64][58]="259163904228646.2";
+        results[64][59]="5.528085492354452E-39";
+        results[64][60]="13386218232.43738";
+        results[64][61]="2.555463490907705E-44";
+        results[64][62]="95703.67902257296";
+        results[64][63]="2.173516480484612E-49";
+        results[64][64]="1";
+        results[64][65]="2.358192512703023E-33";
+        results[64][66]="2.102354151798515E+23";
+        results[64][67]="7.612275747389602E-38";
+        results[64][68]="4.485068046429608E+18";
+        results[64][69]="3.381012584485181E-43";
+        results[64][70]="32930660998313.20";
+        results[64][71]="2.066235331649750E-48";
+        results[64][72]="802630922.6602931";
+        results[64][73]="3.915291316913575E-53";
+        results[64][74]="2241.654855774030";
+        results[65][0]="7.654371214175933E+28";
+        results[65][1]="1.683105214594628E+23";
+        results[65][2]="3.776344558103940E+18";
+        results[65][3]="44036296446727.19";
+        results[65][4]="307359356.4002524";
+        results[65][5]="9.589421225506852E+23";
+        results[65][6]="5.959386218061519E+32";
+        results[65][7]="9.196195146831527E+18";
+        results[65][8]="8.785257893845823E+26";
+        results[65][9]="85721680113273.25";
+        results[65][10]="3.128466770111285E+22";
+        results[65][11]="1038788140.761402";
+        results[65][12]="1.394809802928366E+17";
+        results[65][13]="13069.71133696832";
+        results[65][14]="1050901362569.648";
+        results[65][15]="1.128926876100059E+20";
+        results[65][16]="1.296911859318036E+36";
+        results[65][17]="1336121001630285";
+        results[65][18]="1.017832441445189E+31";
+        results[65][19]="8611918901.080548";
+        results[65][20]="3.444425037361932E+26";
+        results[65][21]="160569.5680407179";
+        results[65][22]="1.978821499094838E+21";
+        results[65][23]="1.759855262899042";
+        results[65][24]="1.048157675788096E+16";
+        results[65][25]="1.049275613776351E+16";
+        results[65][26]="2.810456431535270E+40";
+        results[65][27]="122322331723.2581";
+        results[65][28]="4.334354938206963E+35";
+        results[65][29]="2088062.137617592";
+        results[65][30]="9.768430666746378E+29";
+        results[65][31]="25.47720569790407";
+        results[65][32]="1.985973237165517E+25";
+        results[65][33]="0.0001096248878581826";
+        results[65][34]="5.254005362366659E+20";
+        results[65][35]="1289740269632.112";
+        results[65][36]="2.717715789811575E+44";
+        results[65][37]="10912219.60636705";
+        results[65][38]="1.330067779429277E+39";
+        results[65][39]="116.3022524136263";
+        results[65][40]="2.411530038110238E+34";
+        results[65][41]="0.001861979227937033";
+        results[65][42]="8.708934379831493E+28";
+        results[65][43]="3.358946592354670E-8";
+        results[65][44]="2.287767799039069E+24";
+        results[65][45]="294630428.7305122";
+        results[65][46]="1.604141798821501E+48";
+        results[65][47]="1071.057296746282";
+        results[65][48]="1.328325270880074E+43";
+        results[65][49]="0.04535998166087906";
+        results[65][50]="4.476648025921479E+38";
+        results[65][51]="1.129048577943026E-7";
+        results[65][52]="8.021629202205431E+33";
+        results[65][53]="2.351814230372703E-12";
+        results[65][54]="3.271310925672783E+28";
+        results[65][55]="11911.22678671919";
+        results[65][56]="1.374967519812914E+52";
+        results[65][57]="0.1194710109580630";
+        results[65][58]="1.098993838851543E+47";
+        results[65][59]="0.000002344204496696504";
+        results[65][60]="5.676473892750065E+42";
+        results[65][61]="1.083653466433309E-11";
+        results[65][62]="4.058348862827780E+37";
+        results[65][63]="9.216874656230971E-17";
+        results[65][64]="4.240535896086675E+32";
+        results[65][65]="1";
+        results[65][66]="8.915108246988459E+55";
+        results[65][67]="0.00003228012855771563";
+        results[65][68]="1.901909204727609E+51";
+        results[65][69]="1.433730522963019E-10";
+        results[65][70]="1.396436500452086E+46";
+        results[65][71]="8.761945093623320E-16";
+        results[65][72]="3.403585238850141E+41";
+        results[65][73]="1.660293337300849E-20";
+        results[65][74]="9.505817882546773E+35";
+        results[66][0]="8.585842148087876E-28";
+        results[66][1]="1.887924597172652E-33";
+        results[66][2]="4.235893108061360E-38";
+        results[66][3]="4.939513377372926E-43";
+        results[66][4]="3.447623381399535E-48";
+        results[66][5]="1.075637104994903E-32";
+        results[66][6]="6.684592102484691E-24";
+        results[66][7]="1.031529275030174E-37";
+        results[66][8]="9.854347979244672E-30";
+        results[66][9]="9.615326896589304E-43";
+        results[66][10]="3.509174183238983E-34";
+        results[66][11]="1.165199694700630E-47";
+        results[66][12]="1.564546121354764E-39";
+        results[66][13]="1.466018243960560E-52";
+        results[66][14]="1.178786991088576E-44";
+        results[66][15]="1.266307536401941E-36";
+        results[66][16]="1.454734842682516E-20";
+        results[66][17]="1.498715399312880E-41";
+        results[66][18]="1.141693867585976E-25";
+        results[66][19]="9.659915126649943E-47";
+        results[66][20]="3.863581845487368E-30";
+        results[66][21]="1.801094990573543E-51";
+        results[66][22]="2.219627002020180E-35";
+        results[66][23]="1.974014464146888E-56";
+        results[66][24]="1.175709421298576E-40";
+        results[66][25]="1.176963402694295E-40";
+        results[66][26]="3.152464730290456E-16";
+        results[66][27]="1.372079040819037E-45";
+        results[66][28]="4.861808536840948E-21";
+        results[66][29]="2.342161283709532E-50";
+        results[66][30]="1.095716439567200E-26";
+        results[66][31]="2.857756181088471E-55";
+        results[66][32]="2.227649044907988E-31";
+        results[66][33]="1.229652908535508E-60";
+        results[66][34]="5.893372482764269E-36";
+        results[66][35]="1.446690532409171E-44";
+        results[66][36]="3.048438352646615E-12";
+        results[66][37]="1.224014258049331E-49";
+        results[66][38]="1.491925552197951E-17";
+        results[66][39]="1.304552330622721E-54";
+        results[66][40]="2.704992436771430E-22";
+        results[66][41]="2.088566034591912E-59";
+        results[66][42]="9.768736552103434E-28";
+        results[66][43]="3.767701411241225E-64";
+        results[66][44]="2.566169401041071E-32";
+        results[66][45]="3.304844097995546E-48";
+        results[66][46]="1.799352015005968E-8";
+        results[66][47]="1.201395728546636E-53";
+        results[66][48]="1.489970995392888E-13";
+        results[66][49]="5.087990005752511E-58";
+        results[66][50]="5.021417465608115E-18";
+        results[66][51]="1.266444048309139E-63";
+        results[66][52]="8.997792264513616E-23";
+        results[66][53]="2.638009730467547E-68";
+        results[66][54]="3.669401240055428E-28";
+        results[66][55]="1.336072031513787E-52";
+        results[66][56]="0.0001542289203585813";
+        results[66][57]="1.340096021811295E-57";
+        results[66][58]="1.232731906786197E-9";
+        results[66][59]="2.629473957860669E-62";
+        results[66][60]="6.367251788185060E-14";
+        results[66][61]="1.215524743403277E-67";
+        results[66][62]="4.552214903502375E-19";
+        results[66][63]="1.033848877756975E-72";
+        results[66][64]="4.756572526776819E-24";
+        results[66][65]="1.121691371877399E-56";
+        results[66][66]="1";
+        results[66][67]="3.620834168628286E-61";
+        results[66][68]="0.00002133355145037165";
+        results[66][69]="1.608203157204890E-66";
+        results[66][70]="1.566370773931775E-10";
+        results[66][71]="9.828198212380789E-72";
+        results[66][72]="3.817772195867480E-15";
+        results[66][73]="1.862336711235894E-76";
+        results[66][74]="1.066259390149060E-20";
+        results[67][0]="2.371233187776874E+33";
+        results[67][1]="5.214059825026099E+27";
+        results[67][2]="1.169866641439169E+23";
+        results[67][3]="1.364192102518798E+18";
+        results[67][4]="9521627395340.313";
+        results[67][5]="2.970688672556348E+28";
+        results[67][6]="1.846146990216091E+37";
+        results[67][7]="2.848871909041218E+23";
+        results[67][8]="2.721568434319621E+31";
+        results[67][9]="2.655555722462696E+18";
+        results[67][10]="9.691618063161386E+26";
+        results[67][11]="32180421428746.45";
+        results[67][12]="4.320954919477782E+21";
+        results[67][13]="404884116.6663938";
+        results[67][14]="3.255567463712780E+16";
+        results[67][15]="3.497281226998773E+24";
+        results[67][16]="4.017678730737416E+40";
+        results[67][17]="4.139143991453913E+19";
+        results[67][18]="3.153123878132466E+35";
+        results[67][19]="266787007544990.6";
+        results[67][20]="1.067041920605562E+31";
+        results[67][21]="4974254292.501521";
+        results[67][22]="6.130153712234388E+25";
+        results[67][23]="54518.22348701272";
+        results[67][24]="3.247067848301876E+20";
+        results[67][25]="3.250531087260965E+20";
+        results[67][26]="8.706459847302905E+44";
+        results[67][27]="3789400389299890";
+        results[67][28]="1.342731622167273E+40";
+        results[67][29]="64685682211.09210";
+        results[67][30]="3.026143668938864E+34";
+        results[67][31]="789253.5388250330";
+        results[67][32]="6.152308946399247E+29";
+        results[67][33]="3.396048676267737";
+        results[67][34]="1.627628388459699E+25";
+        results[67][35]="3.995461998628989E+16";
+        results[67][36]="8.419160366577858E+48";
+        results[67][37]="338047588219.9918";
+        results[67][38]="4.120391828834159E+43";
+        results[67][39]="3602905.490468613";
+        results[67][40]="7.470633314853486E+38";
+        results[67][41]="57.68190249329044";
+        results[67][42]="2.697924317203462E+33";
+        results[67][43]="0.001040561714724588";
+        results[67][44]="7.087232614171990E+28";
+        results[67][45]="9127300351475.501";
+        results[67][46]="4.969440552113530E+52";
+        results[67][47]="33180081.51148695";
+        results[67][48]="4.114993744541877E+47";
+        results[67][49]="1405.198296524041";
+        results[67][50]="1.386812328803897E+43";
+        results[67][51]="0.003497658244837316";
+        results[67][52]="2.485005345583759E+38";
+        results[67][53]="7.285640842996488E-8";
+        results[67][54]="1.013413227219280E+33";
+        results[67][55]="368995642.7968486";
+        results[67][56]="4.259485885734702E+56";
+        results[67][57]="3701.069862359855";
+        results[67][58]="3.404552236793557E+51";
+        results[67][59]="0.07262066792903739";
+        results[67][60]="1.758504115806338E+47";
+        results[67][61]="3.357029587090330E-7";
+        results[67][62]="1.257228221867707E+42";
+        results[67][63]="2.855278175163260E-12";
+        results[67][64]="1.313667598474634E+37";
+        results[67][65]="30978.81094903443";
+        results[67][66]="2.761794529736332E+60";
+        results[67][67]="1";
+        results[67][68]="5.891888569548503E+55";
+        results[67][69]="0.000004441526682273164";
+        results[67][70]="4.325994234983640E+50";
+        results[67][71]="2.714346406011766E-11";
+        results[67][72]="1.054390236632627E+46";
+        results[67][73]="5.143391341618445E-16";
+        results[67][74]="2.944789350993672E+40";
+        results[68][0]="4.024572358737908E-23";
+        results[68][1]="8.849556069295544E-29";
+        results[68][2]="1.985554593624666E-33";
+        results[68][3]="2.315373222720905E-38";
+        results[68][4]="1.616056937083241E-43";
+        results[68][5]="5.041997379091630E-28";
+        results[68][6]="3.133370511719575E-19";
+        results[68][7]="4.835244040026928E-33";
+        results[68][8]="4.619178387700187E-25";
+        results[68][9]="4.507138400728770E-38";
+        results[68][10]="1.644908580459467E-29";
+        results[68][11]="5.461817725994849E-43";
+        results[68][12]="7.333734962012186E-35";
+        results[68][13]="6.871890258736175E-48";
+        results[68][14]="5.525507526633783E-40";
+        results[68][15]="5.935755888314043E-32";
+        results[68][16]="6.818999856009313E-16";
+        results[68][17]="7.025156607418828E-37";
+        results[68][18]="5.351635287926178E-21";
+        results[68][19]="4.528038919877851E-42";
+        results[68][20]="1.811035473617807E-25";
+        results[68][21]="8.442546449724692E-47";
+        results[68][22]="1.040439519497590E-30";
+        results[68][23]="9.253098194827277E-52";
+        results[68][24]="5.511081565737588E-36";
+        results[68][25]="5.516959543432190E-36";
+        results[68][26]="1.477702733941909E-11";
+        results[68][27]="6.431554746104564E-41";
+        results[68][28]="2.278949451126784E-16";
+        results[68][29]="1.097876876786368E-45";
+        results[68][30]="5.136118297584773E-22";
+        results[68][31]="1.339559513912385E-50";
+        results[68][32]="1.044199813655115E-26";
+        results[68][33]="5.763939076885797E-56";
+        results[68][34]="2.762490106944477E-31";
+        results[68][35]="6.781292537131541E-40";
+        results[68][36]="1.428940867974192E-7";
+        results[68][37]="5.737508172967645E-45";
+        results[68][38]="6.993329524475215E-13";
+        results[68][39]="6.115026528318585E-50";
+        results[68][40]="1.267952240893443E-17";
+        results[68][41]="9.790053191333628E-55";
+        results[68][42]="4.579048441525779E-23";
+        results[68][43]="1.766091979577825E-59";
+        results[68][44]="1.202879608212802E-27";
+        results[68][45]="1.549129832266147E-43";
+        results[68][46]="0.0008434376335284867";
+        results[68][47]="5.631484899930744E-49";
+        results[68][48]="6.984167633124823E-9";
+        results[68][49]="2.384970930690432E-53";
+        results[68][50]="2.353765371550753E-13";
+        results[68][51]="5.936395781336616E-59";
+        results[68][52]="4.217672001516121E-18";
+        results[68][53]="1.236554418332251E-63";
+        results[68][54]="1.720014245444119E-23";
+        results[68][55]="6.262773615644344E-48";
+        results[68][56]="7.229406726646745";
+        results[68][57]="6.281635877311693E-53";
+        results[68][58]="0.00005778371733623009";
+        results[68][59]="1.232553315830994E-57";
+        results[68][60]="2.984618760264661E-9";
+        results[68][61]="5.697713979929495E-63";
+        results[68][62]="2.133828919245919E-14";
+        results[68][63]="4.846117066640417E-68";
+        results[68][64]="2.229620575759295E-19";
+        results[68][65]="5.257874547924172E-52";
+        results[68][66]="46874.52074382950";
+        results[68][67]="1.697248663473332E-56";
+        results[68][68]="1";
+        results[68][69]="7.538375225269271E-62";
+        results[68][70]="0.000007342287933519324";
+        results[68][71]="4.606920809807113E-67";
+        results[68][72]="1.789562419904057E-10";
+        results[68][73]="8.729614080282214E-72";
+        results[68][74]="4.998039790184512E-16";
+        results[69][0]="5.338779562533849E+38";
+        results[69][1]="1.173934144274364E+33";
+        results[69][2]="2.633929108448886E+28";
+        results[69][3]="3.071448625904928E+23";
+        results[69][4]="2.143773543755267E+18";
+        results[69][5]="6.688440450921611E+33";
+        results[69][6]="4.156559494698874E+42";
+        results[69][7]="6.414172677182188E+28";
+        results[69][8]="6.127551693389194E+36";
+        results[69][9]="5.978925519149620E+23";
+        results[69][10]="2.182046570122424E+32";
+        results[69][11]="7.245351369200056E+18";
+        results[69][12]="9.728535318099962E+26";
+        results[69][13]="91158771663435.09";
+        results[69][14]="7.329838806791966E+21";
+        results[69][15]="7.874052048267494E+29";
+        results[69][16]="9.045715624703119E+45";
+        results[69][17]="9.319191997593739E+24";
+        results[69][18]="7.099189318657215E+40";
+        results[69][19]="6.006651015061551E+19";
+        results[69][20]="2.402421502642987E+36";
+        results[69][21]="1119942454101324";
+        results[69][22]="1.380190675584772E+31";
+        results[69][23]="12274658554.81710";
+        results[69][24]="7.310702108942491E+25";
+        results[69][25]="7.318499515570511E+25";
+        results[69][26]="1.960240356553922E+50";
+        results[69][27]="8.531751941115174E+20";
+        results[69][28]="3.023130824647137E+45";
+        results[69][29]="1.456383960705739E+16";
+        results[69][30]="6.813296160116931E+39";
+        results[69][31]="177698704811.3589";
+        results[69][32]="1.385178878009241E+35";
+        results[69][33]="764612.9178559042";
+        results[69][34]="3.664569651142300E+30";
+        results[69][35]="8.995695139186061E+21";
+        results[69][36]="1.895555508014859E+54";
+        results[69][37]="7.611067373954845E+16";
+        results[69][38]="9.276971914362904E+48";
+        results[69][39]="811186276297.3776";
+        results[69][40]="1.681996720782961E+44";
+        results[69][41]="12986953.95065576";
+        results[69][42]="6.074317481804861E+38";
+        results[69][43]="234.2801899350586";
+        results[69][44]="1.595674893152901E+34";
+        results[69][45]="2.054991673899878E+18";
+        results[69][46]="1.118858651001097E+58";
+        results[69][47]="7470422646319.768";
+        results[69][48]="9.264818245864578E+52";
+        results[69][49]="316377317.3157802";
+        results[69][50]="3.122377569719179E+48";
+        results[69][51]="787.4900895669555";
+        results[69][52]="5.594935082798914E+43";
+        results[69][53]="0.01640346071109881";
+        results[69][54]="2.281677674624746E+38";
+        results[69][55]="83078560412474.54";
+        results[69][56]="9.590139135570173E+61";
+        results[69][57]="833287769.5256027";
+        results[69][58]="7.665274758748302E+56";
+        results[69][59]="16350.38425388234";
+        results[69][60]="3.959233483443444E+52";
+        results[69][61]="0.07558278554283523";
+        results[69][62]="2.830621792469476E+47";
+        results[69][63]="6.428596244978392E-7";
+        results[69][64]="2.957693812169788E+42";
+        results[69][65]="6974811402.726853";
+        results[69][66]="6.218119865763931E+65";
+        results[69][67]="225147.8087458437";
+        results[69][68]="1.326545800808529E+61";
+        results[69][69]="1";
+        results[69][70]="9.739881226537191E+55";
+        results[69][71]="0.000006111291454907054";
+        results[69][72]="2.373936513408476E+51";
+        results[69][73]="1.158023290087738E-10";
+        results[69][74]="6.630128695943206E+45";
+        results[70][0]="5.481360027253576E-18";
+        results[70][1]="1.205285893092693E-23";
+        results[70][2]="2.704272308036475E-28";
+        results[70][3]="3.153476469031765E-33";
+        results[70][4]="2.201026371773776E-38";
+        results[70][5]="6.867065722216763E-23";
+        results[70][6]="4.267566922042078E-14";
+        results[70][7]="6.585473198283149E-28";
+        results[70][8]="6.291197552485674E-20";
+        results[70][9]="6.138602083626537E-33";
+        results[70][10]="2.240321539216762E-24";
+        results[70][11]="7.438849818270307E-38";
+        results[70][12]="9.988351081318820E-30";
+        results[70][13]="9.359330934659115E-43";
+        results[70][14]="7.525593625126715E-35";
+        results[70][15]="8.084340933043336E-27";
+        results[70][16]="9.287295619229160E-11";
+        results[70][17]="9.568075606715566E-32";
+        results[70][18]="7.288784281388184E-16";
+        results[70][19]="6.167068032304013E-37";
+        results[70][20]="2.466581929251223E-20";
+        results[70][21]="1.149852270323317E-41";
+        results[70][22]="1.417050827913914E-25";
+        results[70][23]="1.260247252438118E-46";
+        results[70][24]="7.505945851807534E-31";
+        results[70][25]="7.513951500384414E-31";
+        results[70][26]="0.000002012591643533670";
+        results[70][27]="8.759605730991504E-36";
+        results[70][28]="3.103868265262150E-11";
+        results[70][29]="1.495278973975256E-40";
+        results[70][30]="6.995255898556019E-17";
+        results[70][31]="1.824444268654967E-45";
+        results[70][32]="1.422172248091892E-21";
+        results[70][33]="7.850331026344006E-51";
+        results[70][34]="3.762437719628292E-26";
+        results[70][35]="9.235939258352015E-35";
+        results[70][36]="0.01946179284866684";
+        results[70][37]="7.814332841367511E-40";
+        results[70][38]="9.524727970077244E-8";
+        results[70][39]="8.328502755118070E-45";
+        results[70][40]="1.726917075949764E-12";
+        results[70][41]="1.333379088368309E-49";
+        results[70][42]="6.236541637956356E-18";
+        results[70][43]="2.405370091133565E-54";
+        results[70][44]="1.638289888797966E-22";
+        results[70][45]="2.109873443118451E-38";
+        results[70][46]="114.8739522564880";
+        results[70][47]="7.669931976137371E-44";
+        results[70][48]="0.0009512249718838192";
+        results[70][49]="3.248266687829637E-48";
+        results[70][50]="3.205765550006891E-8";
+        results[70][51]="8.085212450243923E-54";
+        results[70][52]="5.744356581633671E-13";
+        results[70][53]="1.684154080483660E-58";
+        results[70][54]="2.342613448311986E-18";
+        results[70][55]="8.529730340665701E-43";
+        results[70][56]="984625.8812110530";
+        results[70][57]="8.555420237109612E-48";
+        results[70][58]="7.869987919219759";
+        results[70][59]="1.678704685775246E-52";
+        results[70][60]="0.0004064971010792362";
+        results[70][61]="7.760134213639389E-58";
+        results[70][62]="2.906217978056231E-9";
+        results[70][63]="6.600281970033780E-63";
+        results[70][64]="3.036683654941584E-14";
+        results[70][65]="7.161084658530892E-47";
+        results[70][66]="6384184489.665129";
+        results[70][67]="2.311607333900624E-51";
+        results[70][68]="136197.3282789357";
+        results[70][69]="1.026706565245795E-56";
+        results[70][70]="1";
+        results[70][71]="6.274503058883598E-62";
+        results[70][72]="0.00002437336203793195";
+        results[70][73]="1.188950114640616E-66";
+        results[70][74]="6.807196660549431E-11";
+        results[71][0]="8.735926934473208E+43";
+        results[71][1]="1.920926457094031E+38";
+        results[71][2]="4.309938624075892E+33";
+        results[71][3]="5.025858525269176E+28";
+        results[71][4]="3.507889550962140E+23";
+        results[71][5]="1.094439775990578E+39";
+        results[71][6]="6.801442093489699E+47";
+        results[71][7]="1.049560919244317E+34";
+        results[71][8]="1.002660687778045E+42";
+        results[71][9]="9.783407587849290E+28";
+        results[71][10]="3.570516291397545E+37";
+        results[71][11]="1.185567964261042E+24";
+        results[71][12]="1.591895164857249E+32";
+        results[71][13]="1.491644971215360E+19";
+        results[71][14]="1.199392773340319E+27";
+        results[71][15]="1.288443221267910E+35";
+        results[71][16]="1.480164330477132E+51";
+        results[71][17]="1.524913689087910E+30";
+        results[71][18]="1.161651243610208E+46";
+        results[71][19]="9.828775242323811E+24";
+        results[71][20]="3.931119175659616E+41";
+        results[71][21]="1.832579025832696E+20";
+        results[71][22]="2.258427184775404E+36";
+        results[71][23]="2008521217714331";
+        results[71][24]="1.196261406101385E+31";
+        results[71][25]="1.197537307714907E+31";
+        results[71][26]="3.207571379990312E+55";
+        results[71][27]="1.396063664131845E+26";
+        results[71][28]="4.946795365519211E+50";
+        results[71][29]="2.383103426586433E+21";
+        results[71][30]="1.114870107307058E+45";
+        results[71][31]="2.907711178930534E+16";
+        results[71][32]="2.266589456958420E+40";
+        results[71][33]="125114785229.5539";
+        results[71][34]="5.996391561721113E+35";
+        results[71][35]="1.471979401663617E+27";
+        results[71][36]="3.101726569582645E+59";
+        results[71][37]="1.245410635397457E+22";
+        results[71][38]="1.518005152072067E+54";
+        results[71][39]="1.327356553492530E+17";
+        results[71][40]="2.752277048466415E+49";
+        results[71][41]="2125075206522.494";
+        results[71][42]="9.939498920359126E+43";
+        results[71][43]="38335627.03787325";
+        results[71][44]="2.611027317101128E+39";
+        results[71][45]="3.362614414748335E+23";
+        results[71][46]="1.830805582186251E+63";
+        results[71][47]="1.222396722761668E+18";
+        results[71][48]="1.516016428642984E+58";
+        results[71][49]="51769305988793.17";
+        results[71][50]="5.109194337658483E+53";
+        results[71][51]="128858211.9471067";
+        results[71][52]="9.155078143600022E+48";
+        results[71][53]="2684.123451177847";
+        results[71][54]="3.733544196771496E+43";
+        results[71][55]="1.359427234414859E+19";
+        results[71][56]="1.569249185107967E+67";
+        results[71][57]="136352156606197.4";
+        results[71][58]="1.254280672965365E+62";
+        results[71][59]="2675438469.025040";
+        results[71][60]="6.478554512834406E+57";
+        results[71][61]="12367.72719817611";
+        results[71][62]="4.631789881656898E+52";
+        results[71][63]="0.1051921069779213";
+        results[71][64]="4.839719777715578E+47";
+        results[71][65]="1141299094338961";
+        results[71][66]="1.017480496822173E+71";
+        results[71][67]="36841281488.06609";
+        results[71][68]="2.170647252870554E+66";
+        results[71][69]="163631.5347383819";
+        results[71][70]="1.593751713267834E+61";
+        results[71][71]="1";
+        results[71][72]="3.884508750605123E+56";
+        results[71][73]="0.00001894891282198470";
+        results[71][74]="1.084898134030173E+51";
+        results[72][0]="2.248914211639332E-13";
+        results[72][1]="4.945094941013564E-19";
+        results[72][2]="1.109519607441867E-23";
+        results[72][3]="1.293820878762663E-28";
+        results[72][4]="9.030458614401850E-34";
+        results[72][5]="2.817447060249479E-18";
+        results[72][6]="1.750914344685201E-9";
+        results[72][7]="2.701914158594232E-23";
+        results[72][8]="2.581177575212958E-15";
+        results[72][9]="2.518570098812429E-28";
+        results[72][10]="9.191680391610227E-20";
+        results[72][11]="3.052040915280100E-33";
+        results[72][12]="4.098060442286985E-25";
+        results[72][13]="3.839983552574039E-38";
+        results[72][14]="3.087630509658344E-30";
+        results[72][15]="3.316875579356586E-22";
+        results[72][16]="0.000003810428616608354";
+        results[72][17]="3.925628147575576E-27";
+        results[72][18]="2.990471429442005E-11";
+        results[72][19]="2.530249221550267E-32";
+        results[72][20]="1.011999052659421E-15";
+        results[72][21]="4.717659666868350E-37";
+        results[72][22]="5.813932545327873E-21";
+        results[72][23]="5.170592593983595E-42";
+        results[72][24]="3.079569343009031E-26";
+        results[72][25]="3.082853932375250E-26";
+        results[72][26]="0.08257341110354408";
+        results[72][27]="3.593925908686312E-31";
+        results[72][28]="0.000001273467427444617";
+        results[72][29]="6.134890097017279E-36";
+        results[72][30]="2.870041436084768E-12";
+        results[72][31]="7.485402571116811E-41";
+        results[72][32]="5.834944911902525E-17";
+        results[72][33]="3.220865063312414E-46";
+        results[72][34]="1.543667924750332E-21";
+        results[72][35]="3.789357924433339E-30";
+        results[72][36]="798.4861841537783";
+        results[72][37]="3.206095584682231E-35";
+        results[72][38]="0.003907843306661606";
+        results[72][39]="3.417051263652724E-40";
+        results[72][40]="7.085264122619546E-8";
+        results[72][41]="5.470640801598023E-45";
+        results[72][42]="2.558753129030992E-13";
+        results[72][43]="9.868848160504565E-50";
+        results[72][44]="6.721640971189435E-18";
+        results[72][45]="8.656472750188841E-34";
+        results[72][46]="4713094.241069868";
+        results[72][47]="3.146850222878877E-39";
+        results[72][48]="39.02723680071055";
+        results[72][49]="1.332711787062614E-43";
+        results[72][50]="0.001315274251052358";
+        results[72][51]="3.317233148902893E-49";
+        results[72][52]="2.356817484881160E-8";
+        results[72][53]="6.909814402554038E-54";
+        results[72][54]="9.611367708181607E-14";
+        results[72][55]="3.499611718478145E-38";
+        results[72][56]="40397622604.49307";
+        results[72][57]="3.510151871454961E-43";
+        results[72][58]="322892.9971569699";
+        results[72][59]="6.887456409020225E-48";
+        results[72][60]="16.67792487743833";
+        results[72][61]="3.183858755949381E-53";
+        results[72][62]="0.0001192374680822991";
+        results[72][63]="2.707989960417380E-58";
+        results[72][64]="1.245902658080421E-9";
+        results[72][65]="2.938078319842043E-42";
+        results[72][66]="261932862595217.9";
+        results[72][67]="9.484154587713828E-47";
+        results[72][68]="5587958200.718210";
+        results[72][69]="4.212412566013441E-52";
+        results[72][70]="41028.39807014366";
+        results[72][71]="2.574328091922103E-57";
+        results[72][72]="1";
+        results[72][73]="4.878071858901815E-62";
+        results[72][74]="0.000002792883743307747";
+        results[73][0]="4.610252322411714E+48";
+        results[73][1]="1.013739666829516E+43";
+        results[73][2]="2.274504434405050E+38";
+        results[73][3]="2.652320253137757E+33";
+        results[73][4]="1.851235257619769E+28";
+        results[73][5]="5.775739148057081E+43";
+        results[73][6]="3.589357425085942E+52";
+        results[73][7]="5.538897820177879E+38";
+        results[73][8]="5.291388995229049E+46";
+        results[73][9]="5.163044275816442E+33";
+        results[73][10]="1.884285565584005E+42";
+        results[73][11]="6.256654275624378E+28";
+        results[73][12]="8.400984161003253E+36";
+        results[73][13]="7.871929040091104E+23";
+        results[73][14]="6.329612598928488E+31";
+        results[73][15]="6.799562768440446E+39";
+        results[73][16]="7.811341708004652E+55";
+        results[73][17]="8.047499629206652E+34";
+        results[73][18]="6.130437426797644E+50";
+        results[73][19]="5.186986364157197E+29";
+        results[73][20]="2.074588242919507E+46";
+        results[73][21]="9.671156562114322E+24";
+        results[73][22]="1.191850533058106E+41";
+        results[73][23]="1.059966466985920E+20";
+        results[73][24]="6.313087285479891E+35";
+        results[73][25]="6.319820661824533E+35";
+        results[73][26]="1.692746919110240E+60";
+        results[73][27]="7.367513256550102E+30";
+        results[73][28]="2.610595875336918E+55";
+        results[73][29]="1.257646519868694E+26";
+        results[73][30]="5.883557108424581E+49";
+        results[73][31]="1.534500267243291E+21";
+        results[73][32]="1.196158047826734E+45";
+        results[73][33]="6602742141723014";
+        results[73][34]="3.164504274231525E+40";
+        results[73][35]="7.768146993403301E+31";
+        results[73][36]="1.636888933271145E+64";
+        results[73][37]="6.572464853775255E+26";
+        results[73][38]="8.011040877822095E+58";
+        results[73][39]="7.004921949677867E+21";
+        results[73][40]="1.452472273381932E+54";
+        results[73][41]="1.121476058540394E+17";
+        results[73][42]="5.245419098043044E+48";
+        results[73][43]="2023104301445.511";
+        results[73][44]="1.377929880004403E+44";
+        results[73][45]="1.774568518172187E+28";
+        results[73][46]="9.661797483505934E+67";
+        results[73][47]="6.451012436678859E+22";
+        results[73][48]="8.000545692964971E+62";
+        results[73][49]="2.732046237963053E+18";
+        results[73][50]="2.696299458262718E+58";
+        results[73][51]="6800295782542.430";
+        results[73][52]="4.831452986040559E+53";
+        results[73][53]="141650525.0931179";
+        results[73][54]="1.970321058440780E+48";
+        results[73][55]="7.174170081344397E+23";
+        results[73][56]="8.281473453650119E+71";
+        results[73][57]="7.195777292721534E+18";
+        results[73][58]="6.619275125431665E+66";
+        results[73][59]="141192188394099.9";
+        results[73][60]="3.418958424526566E+62";
+        results[73][61]="652687957.0540302";
+        results[73][62]="2.444356531253368E+57";
+        results[73][63]="5551.353154988210";
+        results[73][64]="2.554088365481576E+52";
+        results[73][65]="6.023032060260553E+19";
+        results[73][66]="5.369598279230475E+75";
+        results[73][67]="1944242492124535";
+        results[73][68]="1.145526011577904E+71";
+        results[73][69]="8635404905.580393";
+        results[73][70]="8.410781812340964E+65";
+        results[73][71]="52773.47620913591";
+        results[73][72]="2.049990301342397E+61";
+        results[73][73]="1";
+        results[73][74]="5.725384586557730E+55";
+        results[74][0]="8.052301557585906E-8";
+        results[74][1]="1.770605365462456E-13";
+        results[74][2]="3.972666639277327E-18";
+        results[74][3]="4.632562604379404E-23";
+        results[74][4]="3.233381495395381E-28";
+        results[74][5]="1.008794965777072E-12";
+        results[74][6]="0.0006269198812448631";
+        results[74][7]="9.674280804091849E-18";
+        results[74][8]="9.241980019390084E-10";
+        results[74][9]="9.017812162240471E-23";
+        results[74][10]="3.291107413129942E-14";
+        results[74][11]="1.092791965506384E-27";
+        results[74][12]="1.467322244295588E-19";
+        results[74][13]="1.374917076937174E-32";
+        results[74][14]="1.105534921407618E-24";
+        results[74][15]="1.187616773274011E-16";
+        results[74][16]="1.364334847713883";
+        results[74][17]="1.405582368754908E-21";
+        results[74][18]="0.00001070746835276518";
+        results[74][19]="9.059629594726956E-27";
+        results[74][20]="3.623491507959662E-10";
+        results[74][21]="1.689171516062104E-31";
+        results[74][22]="2.081695150848690E-15";
+        results[74][23]="1.851345444067719E-36";
+        results[74][24]="1.102648597668354E-20";
+        results[74][25]="1.103824654270814E-20";
+        results[74][26]="29565.64565260007";
+        results[74][27]="1.286815434870144E-25";
+        results[74][28]="0.4559686490696489";
+        results[74][29]="2.196614918797670E-30";
+        results[74][30]="0.000001027626532239985";
+        results[74][31]="2.680169766841597E-35";
+        results[74][32]="2.089218688706290E-11";
+        results[74][33]="1.153239933824738E-40";
+        results[74][34]="5.527147087483460E-16";
+        results[74][35]="1.356790426208511E-24";
+        results[74][36]="285900258.4934282";
+        results[74][37]="1.147951679823628E-29";
+        results[74][38]="1399.214455677041";
+        results[74][39]="1.223484963110475E-34";
+        results[74][40]="0.02536899052671676";
+        results[74][41]="1.958778561659312E-39";
+        results[74][42]="9.161688649454979E-8";
+        results[74][43]="3.533569266587664E-44";
+        results[74][44]="2.406702744894305E-12";
+        results[74][45]="3.099474788713032E-28";
+        results[74][46]="1687536852317.355";
+        results[74][47]="1.126738708841461E-33";
+        results[74][48]="13973813.58756047";
+        results[74][49]="4.771812612164872E-38";
+        results[74][50]="470.9377016512027";
+        results[74][51]="1.187744802071186E-43";
+        results[74][52]="0.008438652308849302";
+        results[74][53]="2.474078779366023E-48";
+        results[74][54]="3.441377655339997E-8";
+        results[74][55]="1.253045969730694E-32";
+        results[74][56]="1.446448413805017E+16";
+        results[74][57]="1.256819901603824E-37";
+        results[74][58]="115612759725.7422";
+        results[74][59]="2.466073435932954E-42";
+        results[74][60]="5971578.629938194";
+        results[74][61]="1.139989719793558E-47";
+        results[74][62]="42.69331595631704";
+        results[74][63]="9.696035386027837E-53";
+        results[74][64]="0.0004460990046813902";
+        results[74][65]="1.051987332763925E-36";
+        results[74][66]="9.378580946051059E+19";
+        results[74][67]="3.395828634270787E-41";
+        results[74][68]="2000784391440555";
+        results[74][69]="1.508266348754094E-46";
+        results[74][70]="14690335094.84779";
+        results[74][71]="9.217455248864755E-52";
+        results[74][72]="358052.8557252626";
+        results[74][73]="1.746607559512835E-56";
+        results[74][74]="1";
+    }
+
+    @Test
+    public void mcDivideTests() {
+        for(int i=0; i<value.length; i++) {
+            for(int j=0; j<value.length; j++) {
+                BigDecimal v1 = new BigDecimal(value[i]);
+                BigDecimal v2 = new BigDecimal(value[j]);
+                BigDecimal res1  = v1.divide(v2, MathContext.DECIMAL64);
+                Assert.assertEquals(res1.toString(), results[i][j],
+                    "Unexpected result from " + v1 + " / " + v2 +
+                        "; expected " + results[i][j] + " got " + res1);
+            }
+        }
+        for (int mpc = 1; mpc < 23; mpc++) {
+            for (int i = 0; i < value.length; i++) {
+                for (int j = 0; j < value.length; j++) {
+                    BigDecimal v1 = new BigDecimal(value[i]);
+                    BigDecimal v2 = new BigDecimal(value[j]);
+                    BigDecimal res1 = v1.divide(v2, new MathContext(mpc, RoundingMode.HALF_EVEN));
+                    BigDecimal res2 = v1.divide(v2, new MathContext(128, RoundingMode.HALF_EVEN)).round(new MathContext(mpc, RoundingMode.HALF_EVEN));
+                    Assert.assertEquals(res1, res2, "Unexpected result from " + v1 + " / " + v2 +
+                                           "; expected " + res2 + " got " + res1);
+                }
+            }
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/DivideTests.java b/ojluni/src/test/java/math/BigDecimal/DivideTests.java
new file mode 100644
index 0000000..57773ee
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/DivideTests.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4851776 4907265 6177836 6876282 8066842
+ * @summary Some tests for the divide methods.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class DivideTests {
+
+    // Preliminary exact divide method; could be used for comparison
+    // purposes.
+    BigDecimal anotherDivide(BigDecimal dividend, BigDecimal divisor) {
+        /*
+         * Handle zero cases first.
+         */
+        if (divisor.signum() == 0) {   // x/0
+            if (dividend.signum() == 0)    // 0/0
+                throw new ArithmeticException("Division undefined");  // NaN
+            throw new ArithmeticException("Division by zero");
+        }
+        if (dividend.signum() == 0)        // 0/y
+            return BigDecimal.ZERO;
+        else {
+            /*
+             * Determine if there is a result with a terminating
+             * decimal expansion.  Putting aside overflow and
+             * underflow considerations, the existance of an exact
+             * result only depends on the ratio of the intVal's of the
+             * dividend (i.e. this) and and divisor since the scales
+             * of the argument just affect where the decimal point
+             * lies.
+             *
+             * For the ratio of (a = this.intVal) and (b =
+             * divisor.intVal) to have a finite decimal expansion,
+             * once a/b is put in lowest terms, b must be equal to
+             * (2^i)*(5^j) for some integer i,j >= 0.  Therefore, we
+             * first compute to see if b_prime =(b/gcd(a,b)) is equal
+             * to (2^i)*(5^j).
+             */
+            BigInteger TWO  = BigInteger.valueOf(2);
+            BigInteger FIVE = BigInteger.valueOf(5);
+            BigInteger TEN  = BigInteger.valueOf(10);
+
+            BigInteger divisorIntvalue  = divisor.scaleByPowerOfTen(divisor.scale()).toBigInteger().abs();
+            BigInteger dividendIntvalue = dividend.scaleByPowerOfTen(dividend.scale()).toBigInteger().abs();
+
+            BigInteger b_prime = divisorIntvalue.divide(dividendIntvalue.gcd(divisorIntvalue));
+
+            boolean goodDivisor = false;
+            int i=0, j=0;
+
+            badDivisor: {
+                while(! b_prime.equals(BigInteger.ONE) ) {
+                    int b_primeModTen = b_prime.mod(TEN).intValue() ;
+
+                    switch(b_primeModTen) {
+                    case 0:
+                        // b_prime divisible by 10=2*5, increment i and j
+                        i++;
+                        j++;
+                        b_prime = b_prime.divide(TEN);
+                        break;
+
+                    case 5:
+                        // b_prime divisible by 5, increment j
+                        j++;
+                        b_prime = b_prime.divide(FIVE);
+                        break;
+
+                    case 2:
+                    case 4:
+                    case 6:
+                    case 8:
+                        // b_prime divisible by 2, increment i
+                        i++;
+                        b_prime = b_prime.divide(TWO);
+                        break;
+
+                    default: // hit something we shouldn't have
+                        b_prime = BigInteger.ONE; // terminate loop
+                        break badDivisor;
+                    }
+                }
+
+                goodDivisor = true;
+            }
+
+            if( ! goodDivisor ) {
+                throw new ArithmeticException("Non terminating decimal expansion");
+            }
+            else {
+                // What is a rule for determining how many digits are
+                // needed?  Once that is determined, cons up a new
+                // MathContext object and pass it on to the divide(bd,
+                // mc) method; precision == ?, roundingMode is unnecessary.
+
+                // Are we sure this is the right scale to use?  Should
+                // also determine a precision-based method.
+                MathContext mc = new MathContext(dividend.precision() +
+                                                 (int)Math.ceil(
+                                                      10.0*divisor.precision()/3.0),
+                                                 RoundingMode.UNNECESSARY);
+                // Should do some more work here to rescale, etc.
+                return dividend.divide(divisor, mc);
+            }
+        }
+    }
+
+    @Test
+    public void powersOf2and5() {
+        for(int i = 0; i < 6; i++) {
+            int powerOf2 = (int)StrictMath.pow(2.0, i);
+
+            for(int j = 0; j < 6; j++) {
+                int powerOf5 = (int)StrictMath.pow(5.0, j);
+                int product;
+
+                BigDecimal bd;
+
+                try {
+                    bd = BigDecimal.ONE.divide(new BigDecimal(product=powerOf2*powerOf5));
+                } catch (ArithmeticException e) {
+                    Assert.fail((new BigDecimal(powerOf2)).toString() + " / " +
+                                       (new BigDecimal(powerOf5)).toString() + " threw an exception.");
+                }
+
+                try {
+                    bd = new BigDecimal(powerOf2).divide(new BigDecimal(powerOf5));
+                } catch (ArithmeticException e) {
+                    Assert.fail((new BigDecimal(powerOf2)).toString() + " / " +
+                                       (new BigDecimal(powerOf5)).toString() + " threw an exception.");
+                }
+
+                try {
+                    bd = new BigDecimal(powerOf5).divide(new BigDecimal(powerOf2));
+                } catch (ArithmeticException e) {
+                    Assert.fail((new BigDecimal(powerOf5)).toString() + " / " +
+                                       (new BigDecimal(powerOf2)).toString() + " threw an exception.");
+                }
+
+            }
+        }
+    }
+
+    @Test
+    public void nonTerminating() {
+        int[] primes = {1, 3, 7, 13, 17};
+
+        // For each pair of prime products, verify the ratio of
+        // non-equal products has a non-terminating expansion.
+
+        for(int i = 0; i < primes.length; i++) {
+            for(int j = i+1; j < primes.length; j++) {
+
+                for(int m = 0; m < primes.length; m++) {
+                    for(int n = m+1; n < primes.length; n++) {
+                        int dividend = primes[i] * primes[j];
+                        int divisor  = primes[m] * primes[n];
+
+                        if ( ((dividend/divisor) * divisor) != dividend ) {
+                            try {
+                                BigDecimal quotient = (new BigDecimal(dividend).
+                                                       divide(new BigDecimal(divisor)));
+                                Assert.fail("Exact quotient " + quotient.toString() +
+                                                   " returned for non-terminating fraction " +
+                                                   dividend + " / " + divisor + ".");
+                            }
+                            catch (ArithmeticException e) {
+                                ; // Correct result
+                            }
+                        }
+
+                    }
+                }
+            }
+        }
+    }
+
+    @Test
+    public void properScaleTests(){
+        BigDecimal[][] testCases = {
+            {new BigDecimal("1"),       new BigDecimal("5"),            new BigDecimal("2e-1")},
+            {new BigDecimal("1"),       new BigDecimal("50e-1"),        new BigDecimal("2e-1")},
+            {new BigDecimal("10e-1"),   new BigDecimal("5"),            new BigDecimal("2e-1")},
+            {new BigDecimal("1"),       new BigDecimal("500e-2"),       new BigDecimal("2e-1")},
+            {new BigDecimal("100e-2"),  new BigDecimal("5"),            new BigDecimal("20e-2")},
+            {new BigDecimal("1"),       new BigDecimal("32"),           new BigDecimal("3125e-5")},
+            {new BigDecimal("1"),       new BigDecimal("64"),           new BigDecimal("15625e-6")},
+            {new BigDecimal("1.0000000"),       new BigDecimal("64"),   new BigDecimal("156250e-7")},
+        };
+
+
+        for(BigDecimal[] tc : testCases) {
+            BigDecimal quotient = tc[0].divide(tc[1]);
+            Assert.assertEquals(quotient, tc[2],
+                "Unexpected quotient from " + tc[0] + " / " + tc[1] +
+                                   "; expected " + tc[2] + " got " + quotient);
+        }
+    }
+
+    @Test
+    public void trailingZeroTests() {
+        MathContext mc = new MathContext(3, RoundingMode.FLOOR);
+        BigDecimal[][] testCases = {
+            {new BigDecimal("19"),      new BigDecimal("100"),          new BigDecimal("0.19")},
+            {new BigDecimal("21"),      new BigDecimal("110"),          new BigDecimal("0.190")},
+        };
+
+        for(BigDecimal[] tc : testCases) {
+            BigDecimal quotient = tc[0].divide(tc[1], mc);
+            Assert.assertEquals(quotient, tc[2],
+                "Unexpected quotient from " + tc[0] + " / " + tc[1] +
+                                   "; expected " + tc[2] + " got " + quotient);
+        }
+    }
+
+    @Test
+    public void scaledRoundedDivideTests() {
+        // Tests of the traditional scaled divide under different
+        // rounding modes.
+
+        // Encode rounding mode and scale for the divide in a
+        // BigDecimal with the significand equal to the rounding mode
+        // and the scale equal to the number's scale.
+
+        // {dividend, divisor, rounding, quotient}
+        BigDecimal a = new BigDecimal("31415");
+        BigDecimal a_minus = a.negate();
+        BigDecimal b = new BigDecimal("10000");
+
+        BigDecimal c = new BigDecimal("31425");
+        BigDecimal c_minus = c.negate();
+
+         // Ad hoc tests
+        BigDecimal d = new BigDecimal(new BigInteger("-37361671119238118911893939591735"), 10);
+        BigDecimal e = new BigDecimal(new BigInteger("74723342238476237823787879183470"), 15);
+
+        BigDecimal[][] testCases = {
+            {a,         b,      BigDecimal.valueOf(ROUND_UP, 3),        new BigDecimal("3.142")},
+            {a_minus,   b,      BigDecimal.valueOf(ROUND_UP, 3),        new BigDecimal("-3.142")},
+
+            {a,         b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("3.141")},
+            {a_minus,   b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("-3.141")},
+
+            {a,         b,      BigDecimal.valueOf(ROUND_CEILING, 3),   new BigDecimal("3.142")},
+            {a_minus,   b,      BigDecimal.valueOf(ROUND_CEILING, 3),   new BigDecimal("-3.141")},
+
+            {a,         b,      BigDecimal.valueOf(ROUND_FLOOR, 3),     new BigDecimal("3.141")},
+            {a_minus,   b,      BigDecimal.valueOf(ROUND_FLOOR, 3),     new BigDecimal("-3.142")},
+
+            {a,         b,      BigDecimal.valueOf(ROUND_HALF_UP, 3),   new BigDecimal("3.142")},
+            {a_minus,   b,      BigDecimal.valueOf(ROUND_HALF_UP, 3),   new BigDecimal("-3.142")},
+
+            {a,         b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("3.141")},
+            {a_minus,   b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("-3.141")},
+
+            {a,         b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
+            {a_minus,   b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
+
+            {c,         b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
+            {c_minus,   b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
+
+            {d,         e,      BigDecimal.valueOf(ROUND_HALF_UP, -5),   BigDecimal.valueOf(-1, -5)},
+            {d,         e,      BigDecimal.valueOf(ROUND_HALF_DOWN, -5), BigDecimal.valueOf(0, -5)},
+            {d,         e,      BigDecimal.valueOf(ROUND_HALF_EVEN, -5), BigDecimal.valueOf(0, -5)},
+        };
+
+        for(BigDecimal[] tc : testCases) {
+            int scale = tc[2].scale();
+            int rm = tc[2].unscaledValue().intValue();
+
+            BigDecimal quotient = tc[0].divide(tc[1], scale, rm);
+            Assert.assertEquals(quotient, tc[3],
+                "Unexpected quotient from " + tc[0] + " / " + tc[1] +
+                                   " scale " + scale + " rounding mode " + RoundingMode.valueOf(rm) +
+                                   "; expected " + tc[3] + " got " + quotient);
+        }
+
+        // 6876282
+        BigDecimal[][] testCases2 = {
+            // { dividend, divisor, expected quotient }
+            { new BigDecimal(3090), new BigDecimal(7), new BigDecimal(441) },
+            { new BigDecimal("309000000000000000000000"), new BigDecimal("700000000000000000000"),
+              new BigDecimal(441) },
+            { new BigDecimal("962.430000000000"), new BigDecimal("8346463.460000000000"),
+              new BigDecimal("0.000115309916") },
+            { new BigDecimal("18446744073709551631"), new BigDecimal("4611686018427387909"),
+              new BigDecimal(4) },
+            { new BigDecimal("18446744073709551630"), new BigDecimal("4611686018427387909"),
+              new BigDecimal(4) },
+            { new BigDecimal("23058430092136939523"), new BigDecimal("4611686018427387905"),
+              new BigDecimal(5) },
+            { new BigDecimal("-18446744073709551661"), new BigDecimal("-4611686018427387919"),
+              new BigDecimal(4) },
+            { new BigDecimal("-18446744073709551660"), new BigDecimal("-4611686018427387919"),
+              new BigDecimal(4) },
+        };
+
+        for (BigDecimal[] test : testCases2) {
+            BigDecimal quo = test[0].divide(test[1], RoundingMode.HALF_UP);
+            Assert.assertEquals(quo, test[2], "Unexpected quotient from " + test[0] + " / " + test[1] +
+                                   " rounding mode HALF_UP" +
+                                   "; expected " + test[2] + " got " + quo);
+        }
+    }
+
+    @Test
+    public void divideByOneTests() {
+        //problematic divisor: one with scale 17
+        BigDecimal one = BigDecimal.ONE.setScale(17);
+        RoundingMode rounding = RoundingMode.UNNECESSARY;
+
+        long[][] unscaledAndScale = new long[][] {
+            { Long.MAX_VALUE,  17},
+            {-Long.MAX_VALUE,  17},
+            { Long.MAX_VALUE,   0},
+            {-Long.MAX_VALUE,   0},
+            { Long.MAX_VALUE, 100},
+            {-Long.MAX_VALUE, 100}
+        };
+
+        for (long[] uas : unscaledAndScale) {
+            long unscaled = uas[0];
+            int scale = (int)uas[1];
+
+            BigDecimal noRound = null;
+            try {
+                noRound = BigDecimal.valueOf(unscaled, scale).
+                    divide(one, RoundingMode.UNNECESSARY);
+            } catch (ArithmeticException e) {
+                Assert.fail("ArithmeticException for value " + unscaled
+                    + " and scale " + scale + " without rounding");
+            }
+
+            BigDecimal roundDown = null;
+            try {
+                roundDown = BigDecimal.valueOf(unscaled, scale).
+                        divide(one, RoundingMode.DOWN);
+            } catch (ArithmeticException e) {
+                Assert.fail("ArithmeticException for value " + unscaled
+                    + " and scale " + scale + " with rounding down");
+            }
+
+            if (noRound != null && roundDown != null && noRound.compareTo(roundDown) != 0) {
+                Assert.fail("Equality failure for value " + unscaled
+                        + " and scale " + scale);
+            }
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/EqualsTests.java b/ojluni/src/test/java/math/BigDecimal/EqualsTests.java
new file mode 100644
index 0000000..c28249b
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/EqualsTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 1234567
+ * @summary Test BigDecimal.equals() method.
+ * @author xlu
+ */
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class EqualsTests {
+
+    @Test
+    public void testEquals() {
+        BigDecimal[][] testValues = {
+            // The even index is supposed to return true for equals call and
+            // the odd index is supposed to return false, i.e. not equal.
+            {ZERO, ZERO},
+            {ONE, TEN},
+
+            {valueOf(Integer.MAX_VALUE), valueOf(Integer.MAX_VALUE)},
+            {valueOf(Long.MAX_VALUE), valueOf(-Long.MAX_VALUE)},
+
+            {valueOf(12345678), valueOf(12345678)},
+            {valueOf(123456789), valueOf(123456788)},
+
+            {new BigDecimal("123456789123456789123"),
+             new BigDecimal(new BigInteger("123456789123456789123"))},
+            {new BigDecimal("123456789123456789123"),
+             new BigDecimal(new BigInteger("123456789123456789124"))},
+
+            {valueOf(Long.MIN_VALUE), new BigDecimal("-9223372036854775808")},
+            {new BigDecimal("9223372036854775808"), valueOf(Long.MAX_VALUE)},
+
+            {valueOf(Math.round(Math.pow(2, 10))), new BigDecimal("1024")},
+            {new BigDecimal("1020"), valueOf(Math.pow(2, 11))},
+
+            {new BigDecimal(BigInteger.valueOf(2).pow(65)),
+             new BigDecimal("36893488147419103232")},
+            {new BigDecimal("36893488147419103231.81"),
+             new BigDecimal("36893488147419103231.811"),
+            }
+        };
+
+        boolean expected = Boolean.TRUE;
+        for (BigDecimal[] testValuePair : testValues) {
+            equalsTest(testValuePair[0], testValuePair[1], expected);
+            expected = !expected;
+        }
+    }
+
+    private static void equalsTest(BigDecimal l, BigDecimal r, boolean expected) {
+        boolean result = l.equals(r);
+        Assert.assertEquals(result, expected, l + " .equals(" + r + ") => " + result +
+                               "\n\tExpected " + expected);
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/FloatDoubleValueTests.java b/ojluni/src/test/java/math/BigDecimal/FloatDoubleValueTests.java
new file mode 100644
index 0000000..559ccc3
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/FloatDoubleValueTests.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005, 2018, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6274390 7082971
+ * @summary Verify {float, double}Value methods work with condensed representation
+ * @run main FloatDoubleValueTests
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 FloatDoubleValueTests
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class FloatDoubleValueTests {
+    private static final long two2the24 = 1L<<23;
+    private static final long two2the53 = 1L<<52;
+
+    // Largest long that fits exactly in a float
+    private static final long maxFltLong = (long)(Integer.MAX_VALUE & ~(0xff));
+
+    // Largest long that fits exactly in a double
+    private static final long maxDblLong = Long.MAX_VALUE & ~(0x7ffL);
+
+    static void testDoubleValue0(long i, BigDecimal bd) {
+        Assert.assertFalse(bd.doubleValue() != i || bd.longValue()   != i,
+            "Unexpected equality failure for " + i + "\t" + bd);
+    }
+
+    static void testFloatValue0(long i, BigDecimal bd) {
+        Assert.assertFalse(bd.floatValue() != i || bd.longValue()   != i,
+            "Unexpected equality failure for " + i + "\t" + bd);
+    }
+
+    static void checkFloat(BigDecimal bd, float f) {
+        float fbd = bd.floatValue();
+        Assert.assertEquals(fbd, f, String.format("Bad conversion:"+
+                                           "got %g (%a)\texpected %g (%a)",
+                                           f, f, fbd, fbd));
+    }
+
+    static void checkDouble(BigDecimal bd, double d) {
+        double dbd = bd.doubleValue();
+
+        Assert.assertEquals(dbd, d, String.format("Bad conversion:"+
+                                           "got %g (%a)\texpected %g (%a)",
+                                           d, d, dbd, dbd));
+    }
+
+    // Test integral values that will convert exactly to both float
+    // and double.
+    @Test
+    public void testFloatDoubleValue() {
+        long[] longValues = {
+            Long.MIN_VALUE, // -2^63
+            0,
+            1,
+            2,
+
+            two2the24-1,
+            two2the24,
+            two2the24+1,
+
+            maxFltLong-1,
+            maxFltLong,
+            maxFltLong+1,
+        };
+
+        for(long i : longValues) {
+            BigDecimal bd1 = new BigDecimal(i);
+            BigDecimal bd2 = new BigDecimal(-i);
+
+            testDoubleValue0( i, bd1);
+            testDoubleValue0(-i, bd2);
+
+            testFloatValue0( i, bd1);
+            testFloatValue0(-i, bd2);
+        }
+
+    }
+
+    @Test
+    public void testDoubleValue() {
+        long[] longValues = {
+            Integer.MAX_VALUE-1,
+            Integer.MAX_VALUE,
+            (long)Integer.MAX_VALUE+1,
+
+            two2the53-1,
+            two2the53,
+            two2the53+1,
+
+            maxDblLong,
+        };
+
+        // Test integral values that will convert exactly to double
+        // but not float.
+        for(long i : longValues) {
+            BigDecimal bd1 = new BigDecimal(i);
+            BigDecimal bd2 = new BigDecimal(-i);
+
+            testDoubleValue0( i, bd1);
+            testDoubleValue0(-i, bd2);
+
+            checkFloat(bd1, (float)i);
+            checkFloat(bd2, -(float)i);
+        }
+
+        // Now check values that should not convert the same in double
+        for(long i = maxDblLong; i < Long.MAX_VALUE; i++) {
+            BigDecimal bd1 = new BigDecimal(i);
+            BigDecimal bd2 = new BigDecimal(-i);
+            checkDouble(bd1, (double)i);
+            checkDouble(bd2, -(double)i);
+
+            checkFloat(bd1, (float)i);
+            checkFloat(bd2, -(float)i);
+        }
+
+        checkDouble(new BigDecimal(Long.MIN_VALUE), (double)Long.MIN_VALUE);
+        checkDouble(new BigDecimal(Long.MAX_VALUE), (double)Long.MAX_VALUE);
+    }
+
+    @Test
+    public void testFloatValue() {
+        // Now check values that should not convert the same in float
+        for(long i = maxFltLong; i <= Integer.MAX_VALUE; i++) {
+            BigDecimal bd1 = new BigDecimal(i);
+            BigDecimal bd2 = new BigDecimal(-i);
+            checkFloat(bd1, (float)i);
+            checkFloat(bd2, -(float)i);
+
+            testDoubleValue0( i, bd1);
+            testDoubleValue0(-i, bd2);
+        }
+    }
+
+    @Test
+    public void testFloatValue1() {
+        checkFloat(new BigDecimal("85070591730234615847396907784232501249"), 8.507059e+37f);
+        checkFloat(new BigDecimal("7784232501249e12"), 7.7842326e24f);
+        checkFloat(new BigDecimal("907784232501249e-12"),907.78424f);
+        checkFloat(new BigDecimal("7784e8"),7.7839997e11f);
+        checkFloat(new BigDecimal("9077e-8"),9.077e-5f);
+    }
+
+    @Test
+    public void testDoubleValue1() {
+        checkDouble(new BigDecimal("85070591730234615847396907784232501249"), 8.507059173023462e37);
+        checkDouble(new BigDecimal("7784232501249e12"), 7.784232501249e24);
+        checkDouble(new BigDecimal("907784232501249e-12"), 907.784232501249);
+        checkDouble(new BigDecimal("7784e8"), 7.784e11);
+        checkDouble(new BigDecimal("9077e-8"), 9.077e-5);
+
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/IntegralDivisionTests.java b/ojluni/src/test/java/math/BigDecimal/IntegralDivisionTests.java
new file mode 100644
index 0000000..f5f1ade
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/IntegralDivisionTests.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2003, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4904082 4917089 6337226 6378503
+ * @summary Tests that integral division and related methods return the proper result and scale.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class IntegralDivisionTests {
+
+    @Test
+    public void dividetoIntegralValueTests() {
+        // Exact integer quotient should have the same results from
+        // the exact divide and dividetoIntegralValue
+
+
+        // Rounded results
+        BigDecimal [][] moreTestCases = {
+            {new BigDecimal("11003"),   new BigDecimal("10"),   new BigDecimal("1100")},
+            {new BigDecimal("11003"),   new BigDecimal("1e1"),  new BigDecimal("1100.0")},
+            {new BigDecimal("1e9"),     new BigDecimal("1"),    new BigDecimal("1e9")},
+            {new BigDecimal("1e9"),     new BigDecimal("1.00"), new BigDecimal("1e9")},
+            {new BigDecimal("1e9"),     new BigDecimal("0.1"),  new BigDecimal("1e10")},
+            {new BigDecimal("10e8"),    new BigDecimal("0.1"),  new BigDecimal("10e9")},
+            {new BigDecimal("400e1"),   new BigDecimal("5"),    new BigDecimal("80e1")},
+            {new BigDecimal("400e1"),   new BigDecimal("4.999999999"),  new BigDecimal("8e2")},
+            {new BigDecimal("40e2"),    new BigDecimal("5"),    new BigDecimal("8e2")},
+            {BigDecimal.valueOf(1, Integer.MIN_VALUE),
+                BigDecimal.valueOf(1, -(Integer.MAX_VALUE & 0x7fffff00)),
+                BigDecimal.valueOf(1, -256)},
+        };
+
+        for(BigDecimal [] testCase: moreTestCases) {
+            BigDecimal quotient = testCase[0].divideToIntegralValue(testCase[1]);
+            Assert.assertEquals(quotient, testCase[2],
+                "dividend  = " + testCase[0] + " scale = " + testCase[0].scale() +
+                " divisor   = " + testCase[1] + " scale = " + testCase[1].scale() +
+                " quotient  = " + quotient    + " scale = " + quotient.scale() +
+                " expected  = " + testCase[2] + " scale = " + testCase[2].scale());
+        }
+    }
+
+    @Test
+    public void dividetoIntegralValueRoundedTests() {
+        BigDecimal dividend = new BigDecimal("11003");
+        BigDecimal divisor = new BigDecimal("10");
+        BigDecimal [] quotients = {     // Expected results with precision =
+            new BigDecimal("1100"),     // 0
+            null,                       // 1
+            new BigDecimal("11e2"),     // 2
+            new BigDecimal("110e1"),    // 3
+            new BigDecimal("1100"),     // 4
+        };
+        divideContextTestPrecs(dividend, divisor, quotients);
+
+        dividend = new BigDecimal("11003");
+        divisor = new BigDecimal("1e1");
+        BigDecimal [] quotients2 = {    // Expected results with precision =
+            new BigDecimal("1100.0"),   // 0
+            null,                       // 1
+            new BigDecimal("11e2"),     // 2
+            new BigDecimal("110e1"),    // 3
+            new BigDecimal("1100"),     // 4
+            new BigDecimal("1100.0"),   // 5
+        };
+        divideContextTestPrecs(dividend, divisor, quotients2);
+
+        dividend = new BigDecimal("1230000");
+        divisor = new BigDecimal("100");
+        BigDecimal [] quotients3 = {    // Expected results with precision =
+            new BigDecimal("12300"),    // 0
+            null,                       // 1
+            null,                       // 2
+            new BigDecimal("123e2"),    // 3
+            new BigDecimal("1230e1"),   // 4
+            new BigDecimal("12300"),    // 5
+        };
+        divideContextTestPrecs(dividend, divisor, quotients3);
+
+        dividend = new BigDecimal("33");
+        divisor  = new BigDecimal("3");
+        BigDecimal [] quotients4 = {    // Expected results with precision =
+            new BigDecimal("11"),       // 0
+            null,                       // 1
+            new BigDecimal("11"),       // 2
+            new BigDecimal("11"),       // 3
+        };
+        divideContextTestPrecs(dividend, divisor, quotients4);
+
+        dividend = new BigDecimal("34");
+        divisor  = new BigDecimal("3");
+        BigDecimal [] quotients5 = {    // Expected results with precision =
+            new BigDecimal("11"),       // 0
+            null,                       // 1
+            new BigDecimal("11"),       // 2
+            new BigDecimal("11"),       // 3
+        };
+        divideContextTestPrecs(dividend, divisor, quotients5);
+    }
+
+    static void divideContextTestPrecs(BigDecimal dividend,
+                                      BigDecimal divisor,
+                                      BigDecimal[] quotients) {
+        for(int i = 0; i < quotients.length; i++) {
+            BigDecimal result = null;
+            BigDecimal quotient = quotients[i];
+
+            try {
+                result = dividend.divideToIntegralValue(divisor,
+                                                        new MathContext(i, RoundingMode.DOWN));
+            } catch (ArithmeticException e) {
+                if (quotient != null) {
+                    Assert.fail("Unexpected exception:" +
+                            " dividend  = " + dividend     + " scale = " + dividend.scale() +
+                            " divisor   = " + divisor      + " scale = " + divisor.scale() +
+                            " expected  = " + quotient     + " scale = " + quotient.scale());
+                }
+            }
+
+            if (quotient != null) {
+                Assert.assertEquals(quotient, result, "Unexpected result: " +
+                    " dividend  = " + dividend     + " scale = " + dividend.scale() +
+                    " divisor   = " + divisor      + " scale = " + divisor.scale() +
+                    " quotient  = " + result       + " scale = " + result.scale() +
+                    " expected  = " + quotient     + " scale = " + quotient.scale() +
+                    " precision = " + i);
+            } else {
+                if (result != null) {
+                    Assert.fail("Unexpected unexceptional result:" +
+                    " dividend  = " + dividend     + " scale = " + dividend.scale() +
+                    " divisor   = " + divisor      + " scale = " + divisor.scale() +
+                    " quotient  = " + result       + " scale = " + result.scale() +
+                    " precision = " + i);
+                }
+            }
+        }
+    }
+
+
+    static void divideContextTests(BigDecimal dividend,
+                                  BigDecimal divisor,
+                                  BigDecimal expected,
+                                  MathContext mc) {
+        divideContextTest(dividend,              divisor,          expected,                mc);
+        divideContextTest(dividend.negate(),     divisor.negate(), expected,                mc);
+
+        if (expected != null) {
+            divideContextTest(dividend.negate(), divisor,          expected.negate(),       mc);
+            divideContextTest(dividend,          divisor.negate(), expected.negate(),       mc);
+        }
+    }
+
+
+    static void divideContextTest(BigDecimal dividend,
+                                 BigDecimal divisor,
+                                 BigDecimal expected,
+                                 MathContext mc) {
+        BigDecimal result = null;
+
+        try {
+            result = dividend.divideToIntegralValue(divisor, mc);
+        } catch (ArithmeticException e) {
+            if (expected != null) {
+                Assert.fail("Unexpected exception:" +
+                        " dividend  = " + dividend     + " scale = " + dividend.scale() +
+                        " divisor   = " + divisor      + " scale = " + divisor.scale() +
+                        " expected  = " + expected     + " scale = " + expected.scale() +
+                        " MathContext  = " + mc);
+            }
+        }
+
+        if (expected != null) {
+            Assert.assertEquals(result, expected, "Unexpected result:" +
+                    " dividend  = " + dividend     + " scale = " + dividend.scale() +
+                    " divisor   = " + divisor      + " scale = " + divisor.scale() +
+                    " expected  = " + expected     + " scale = " + expected.scale() +
+                    " result    = " + result       + " scale = " + result.scale() +
+                    " MathContext  = " + mc);
+        } else {
+            if (result != null) {
+                Assert.fail("Unexpected unexceptional result:" +
+                    "dividend  = " + dividend + " scale = " + dividend.scale() +
+                    "divisor   = " + divisor + " scale = " + divisor.scale() +
+                    "quotient  = " + result + " scale = " + result.scale() +
+                    "MathConext = " + mc);
+            }
+        }
+    }
+
+    @Test
+    public void dividetoIntegralValueScalingTests() {
+        BigDecimal dividend = new BigDecimal("123456789000");
+        BigDecimal divisor = BigDecimal.ONE;
+        BigDecimal expected = new BigDecimal("123456789e3");
+        MathContext mc = new MathContext(9,RoundingMode.DOWN);
+        divideContextTests(dividend, divisor, expected, mc);
+
+
+        // 100/3 = 33 remainder 1
+        int [] precisions = {0, 2, 3, 4};
+        dividend = new BigDecimal(100);
+        divisor  = new BigDecimal(3);
+        expected = new BigDecimal(33);
+
+        for(RoundingMode rm: RoundingMode.values())
+            for(int precision: precisions) {
+                divideContextTests(dividend, divisor, expected, new MathContext(precision, rm));
+            }
+
+        // 123000/10 = 12300 remainder 0
+        dividend = new BigDecimal(123000);
+        divisor  = new BigDecimal(10);
+        int[] precisions1 = {0, 1, 2, 3, 4, 5};
+        BigDecimal[] expected1 = {
+            new BigDecimal("12300"),
+            null,
+            null,
+            new BigDecimal("123e2"),
+            new BigDecimal("1230e1"),
+            new BigDecimal("12300"),
+        };
+
+        for(RoundingMode rm: RoundingMode.values())
+            for(int i = 0; i < precisions1.length; i++) {
+                divideContextTests(dividend, divisor,
+                                               expected1[i],
+                                               new MathContext(precisions1[i], rm));
+            }
+
+        // 123e3/10 = 123e2 remainder 0
+        dividend = new BigDecimal("123e3");
+        divisor  = new BigDecimal(10);
+        int[] precisions2 = {0, 1, 2, 3, 4, 5};
+        BigDecimal[] expected2 = {
+            new BigDecimal("123e2"),
+            null,
+            null,
+            new BigDecimal("123e2"),
+            new BigDecimal("123e2"),
+            new BigDecimal("123e2"),
+        };
+
+        for(RoundingMode rm: RoundingMode.values())
+            for(int i = 0; i < precisions2.length; i++) {
+                divideContextTests(dividend, divisor,
+                                               expected2[i],
+                                               new MathContext(precisions2[i], rm));
+            }
+
+
+        // 123000/1e1 = 12300.0 remainder 0
+        dividend = new BigDecimal("123000");
+        divisor  = new BigDecimal("1e1");
+        int[] precisions3 = {0, 1, 2, 3, 4, 5, 6};
+        BigDecimal[] expected3 = {
+            new BigDecimal("12300.0"),
+            null,
+            null,
+            new BigDecimal("123e2"),
+            new BigDecimal("1230e1"),
+            new BigDecimal("12300"),
+            new BigDecimal("12300.0"),
+        };
+
+        for(RoundingMode rm: RoundingMode.values())
+            for(int i = 0; i < precisions3.length; i++) {
+                divideContextTests(dividend, divisor,
+                                               expected3[i],
+                                               new MathContext(precisions3[i], rm));
+            }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/LongValueExactTests.java b/ojluni/src/test/java/math/BigDecimal/LongValueExactTests.java
new file mode 100644
index 0000000..4d53663
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/LongValueExactTests.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6806261
+ * @summary Tests of BigDecimal.longValueExact
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class LongValueExactTests {
+
+    @Test
+    public static void longValueExactTests() {
+        String[] testStrings = {
+            "9223372036854775807",
+            "9223372036854775807.0",
+            "9223372036854775807.00",
+            "-9223372036854775808",
+            "-9223372036854775808.0",
+            "-9223372036854775808.00",
+        };
+
+        for (String longValue : testStrings) {
+            try {
+                BigDecimal bd = new BigDecimal(longValue);
+                long longValueExact = bd.longValueExact();
+            } catch (Exception e) {
+                Assert.fail("Unexpected exception for longValueExact(" + longValue + "): " + e.getMessage());
+            }
+        }
+
+        // The following Strings are supposed to make longValueExact throw
+        // ArithmeticException.
+        String[] testStrings2 = {
+            "9223372036854775808",
+            "9223372036854775808.0",
+            "9223372036854775808.00",
+            "-9223372036854775809",
+            "-9223372036854775808.1",
+            "-9223372036854775808.01",
+        };
+
+        for (String bigValue : testStrings2) {
+            try {
+                BigDecimal bd = new BigDecimal(bigValue);
+                long longValueExact = bd.longValueExact();
+                Assert.fail("Unexpectedly no throw for longValueExact(" + bigValue + ")");
+            } catch (ArithmeticException e) {
+                // Success;
+            }
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/MultiplyTests.java b/ojluni/src/test/java/math/BigDecimal/MultiplyTests.java
new file mode 100644
index 0000000..a359e45
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/MultiplyTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6850606
+ * @summary Test BigDecimal.multiply(BigDecimal)
+ * @author xlu
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class MultiplyTests {
+
+    @Test
+    public void multiplyTests() {
+        BigDecimal[] bd1 = {
+            new BigDecimal("123456789"),
+            new BigDecimal("1234567898"),
+            new BigDecimal("12345678987")
+        };
+
+        BigDecimal[] bd2 = {
+            new BigDecimal("987654321"),
+            new BigDecimal("8987654321"),
+            new BigDecimal("78987654321")
+        };
+
+        // Two dimensional array recording bd1[i] * bd2[j] &
+        // 0 <= i <= 2 && 0 <= j <= 2;
+        BigDecimal[][] expectedResults = {
+            {new BigDecimal("121932631112635269"),
+             new BigDecimal("1109586943112635269"),
+             new BigDecimal("9751562173112635269")
+            },
+            { new BigDecimal("1219326319027587258"),
+              new BigDecimal("11095869503027587258"),
+              new BigDecimal("97515622363027587258")
+            },
+            { new BigDecimal("12193263197189452827"),
+              new BigDecimal("110958695093189452827"),
+              new BigDecimal("975156224183189452827")
+            }
+        };
+
+        for (int i = 0; i < bd1.length; i++) {
+            for (int j = 0; j < bd2.length; j++) {
+                Assert.assertEquals(bd1[i].multiply(bd2[j]), expectedResults[i][j],
+                    bd1[i] + " * " + bd2[j] + " + is " + bd1[i].multiply(bd2[j]) +
+                        " but expected: " + expectedResults[i][j]);
+            }
+        }
+
+        BigDecimal x = BigDecimal.valueOf(8L, 1);
+        BigDecimal xPower = BigDecimal.valueOf(-1L);
+        try {
+            for (int i = 0; i < 100; i++) {
+                xPower = xPower.multiply(x);
+            }
+        } catch (Exception ex) {
+            Assert.fail("Unexpected exception: " + ex.getMessage());
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/NegateTests.java b/ojluni/src/test/java/math/BigDecimal/NegateTests.java
new file mode 100644
index 0000000..af5805b
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/NegateTests.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2005, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6325535
+ * @summary Test for the rounding behavior of negate(MathContext)
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class NegateTests {
+
+    static BigDecimal negateThenRound(BigDecimal bd, MathContext mc) {
+        return bd.negate().plus(mc);
+    }
+
+
+    static BigDecimal absThenRound(BigDecimal bd, MathContext mc) {
+        return bd.abs().plus(mc);
+    }
+
+
+    static void negateTest(BigDecimal[][] testCases,  MathContext mc) {
+        for (BigDecimal [] testCase : testCases) {
+
+            BigDecimal bd = testCase[0];
+            BigDecimal neg1 = bd.negate(mc);
+            BigDecimal neg2 = negateThenRound(bd, mc);
+            BigDecimal expected = testCase[1];
+
+            Assert.assertEquals(neg1, expected, "(" + bd + ").negate(" + mc + ") => " +
+                                   neg1 + " != expected " + expected);
+
+            Assert.assertEquals(neg1, neg2, "(" + bd + ").negate(" + mc + ")  => " +
+                                   neg1 + " != ntr " + neg2);
+
+            // Test abs consistency
+            BigDecimal abs = bd.abs(mc);
+            BigDecimal expectedAbs = absThenRound(bd,mc);
+            Assert.assertEquals(abs, expectedAbs, "(" + bd + ").abs(" + mc + ")  => " +
+                                   abs + " != atr " +  expectedAbs);
+        }
+    }
+
+    @Test
+    public void negateTests() {
+        BigDecimal [][] testCasesCeiling = {
+            {new BigDecimal("1.3"),     new BigDecimal("-1")},
+            {new BigDecimal("-1.3"),    new BigDecimal("2")},
+        };
+
+        negateTest(testCasesCeiling, new MathContext(1, RoundingMode.CEILING));
+
+        BigDecimal [][] testCasesFloor = {
+            {new BigDecimal("1.3"),     new BigDecimal("-2")},
+            {new BigDecimal("-1.3"),    new BigDecimal("1")},
+        };
+
+        negateTest(testCasesFloor, new MathContext(1, RoundingMode.FLOOR));
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/PowTests.java b/ojluni/src/test/java/math/BigDecimal/PowTests.java
new file mode 100644
index 0000000..5cc30cf
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/PowTests.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4916097
+ * @summary Some exponent over/undeflow tests for the pow method
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class PowTests {
+    @Test
+    public void zeroAndOneTests() {
+        BigDecimal[][] testCases = {
+            {BigDecimal.valueOf(0, Integer.MAX_VALUE),  new BigDecimal(0),              BigDecimal.valueOf(1, 0)},
+            {BigDecimal.valueOf(0, Integer.MAX_VALUE),  new BigDecimal(1),              BigDecimal.valueOf(0, Integer.MAX_VALUE)},
+            {BigDecimal.valueOf(0, Integer.MAX_VALUE),  new BigDecimal(2),              BigDecimal.valueOf(0, Integer.MAX_VALUE)},
+            {BigDecimal.valueOf(0, Integer.MAX_VALUE),  new BigDecimal(999999999),      BigDecimal.valueOf(0, Integer.MAX_VALUE)},
+
+            {BigDecimal.valueOf(0, Integer.MIN_VALUE),  new BigDecimal(0),              BigDecimal.valueOf(1, 0)},
+            {BigDecimal.valueOf(0, Integer.MIN_VALUE),  new BigDecimal(1),              BigDecimal.valueOf(0, Integer.MIN_VALUE)},
+            {BigDecimal.valueOf(0, Integer.MIN_VALUE),  new BigDecimal(2),              BigDecimal.valueOf(0, Integer.MIN_VALUE)},
+            {BigDecimal.valueOf(0, Integer.MIN_VALUE),  new BigDecimal(999999999),      BigDecimal.valueOf(0, Integer.MIN_VALUE)},
+
+            {BigDecimal.valueOf(1, Integer.MAX_VALUE),  new BigDecimal(0),              BigDecimal.valueOf(1, 0)},
+            {BigDecimal.valueOf(1, Integer.MAX_VALUE),  new BigDecimal(1),              BigDecimal.valueOf(1, Integer.MAX_VALUE)},
+            {BigDecimal.valueOf(1, Integer.MAX_VALUE),  new BigDecimal(2),              null}, // overflow
+            {BigDecimal.valueOf(1, Integer.MAX_VALUE),  new BigDecimal(999999999),      null}, // overflow
+
+            {BigDecimal.valueOf(1, Integer.MIN_VALUE),  new BigDecimal(0),              BigDecimal.valueOf(1, 0)},
+            {BigDecimal.valueOf(1, Integer.MIN_VALUE),  new BigDecimal(1),              BigDecimal.valueOf(1, Integer.MIN_VALUE)},
+            {BigDecimal.valueOf(1, Integer.MIN_VALUE),  new BigDecimal(2),              null}, // underflow
+            {BigDecimal.valueOf(1, Integer.MIN_VALUE),  new BigDecimal(999999999),      null}, // underflow
+        };
+
+        for(BigDecimal[] testCase: testCases) {
+            int exponent = testCase[1].intValueExact();
+            BigDecimal result;
+
+            try{
+                result = testCase[0].pow(exponent);
+                Assert.assertEquals(result, testCase[2], "Unexpected result while raising " +
+                                       testCase[0] +
+                                       " to the " + exponent + " power; expected " +
+                                       testCase[2] + ", got " + result + ".");
+            } catch (ArithmeticException e) {
+                if (testCase[2] != null) {
+                    Assert.fail("Unexpected exception while raising " + testCase[0] +
+                                       " to the " + exponent + " power.");
+
+                }
+            }
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/PrecisionTests.java b/ojluni/src/test/java/math/BigDecimal/PrecisionTests.java
new file mode 100644
index 0000000..be48794
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/PrecisionTests.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 1234567
+ * @summary Test that precision() is computed properly.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class PrecisionTests {
+    private static BigDecimal NINE = valueOf(9);
+
+    @Test
+    public void testPrecision() {
+        // Smallest and largest values of a given length
+        BigDecimal[] testValues = {
+            valueOf(1), valueOf(9),
+        };
+
+        testPrecision(new BigDecimal(0), 1);
+
+        for(int i = 1; i < 100; i++) {
+            for(BigDecimal bd : testValues) {
+                testPrecision(bd, i);
+                testPrecision(bd.negate(), i);
+            }
+
+            testValues[0] = testValues[0].multiply(TEN);
+            testValues[1] = testValues[1].multiply(TEN).add(NINE);
+        }
+
+        // The following test tries to cover testings for precision of long values
+        BigDecimal[] randomTestValues = {
+            valueOf(2147483648L),          // 2^31:       10 digits
+            valueOf(-2147483648L),         // -2^31:      10 digits
+            valueOf(98893745455L),         // random:     11 digits
+            valueOf(3455436789887L),       // random:     13 digits
+            valueOf(140737488355328L),     // 2^47:       15 digits
+            valueOf(-140737488355328L),    // -2^47:      15 digits
+            valueOf(7564232235739573L),    // random:     16 digits
+            valueOf(25335434990002322L),   // random:     17 digits
+            valueOf(9223372036854775807L), // 2^63 - 1:   19 digits
+            valueOf(-9223372036854775807L) // -2^63 + 1:  19 digits
+        };
+        // The array below contains the expected precision of the above numbers
+        int[] expectedPrecision = {10, 10, 11, 13, 15, 15, 16, 17, 19, 19};
+        for (int i = 0; i < randomTestValues.length; i++) {
+            testPrecision(randomTestValues[i], expectedPrecision[i]);
+        }
+    }
+
+    private static void testPrecision(BigDecimal bd, int expected) {
+        int precision = bd.precision();
+
+        Assert.assertEquals(precision, expected,
+                String.format("For (%s).precision expected %d, got %d%n", bd, expected, precision));
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/RangeTests.java b/ojluni/src/test/java/math/BigDecimal/RangeTests.java
new file mode 100644
index 0000000..07bcf75
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/RangeTests.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 7036582
+ * @summary Some new tests for the add method and constructor with MathContext.
+ * @run main RangeTests
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 RangeTests
+ * @author Sergey V. Kuksenko
+ */
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class RangeTests {
+
+    private static void addTest(BigDecimal arg1, BigDecimal arg2, BigDecimal expectedResult) {
+        BigDecimal result = arg1.add(arg2);
+        Assert.assertEquals(result, expectedResult, "Sum:" +
+                    arg1 + " + " +
+                    arg2 + " == " +
+                    result + "; expected  " +
+                    expectedResult
+            );
+        result = arg2.add(arg1);
+        Assert.assertEquals(result, expectedResult, "Sum:" +
+                    arg2 + " + " +
+                    arg1 + " == " +
+                    result + "; expected  " +
+                    expectedResult
+            );
+    }
+
+    /*
+     *  Test BigDecimal.add(BigDecimal) when values are withing different ranges:
+     *  1. within 32 bits
+     *  2. within 64 bits
+     *  3. outside 64 bits.
+     */
+    @Test
+    public void addBoundaryTest() {
+        addTest(
+                new BigDecimal("85070591730234615847396907784232501249"),
+                BigDecimal.valueOf(0),
+                new BigDecimal("85070591730234615847396907784232501249") );
+        addTest(
+                new BigDecimal("-85070591730234615847396907784232501249"),
+                BigDecimal.valueOf(0),
+                new BigDecimal("-85070591730234615847396907784232501249") );
+        addTest(
+                new BigDecimal("85070591730234615847396907784232501249"),
+                BigDecimal.valueOf(1),
+                new BigDecimal("85070591730234615847396907784232501250") );
+        addTest(
+                new BigDecimal("85070591730234615847396907784232501249"),
+                BigDecimal.valueOf(-1),
+                new BigDecimal("85070591730234615847396907784232501248") );
+        addTest(
+                new BigDecimal("-85070591730234615847396907784232501250"),
+                BigDecimal.valueOf(-1),
+                new BigDecimal("-85070591730234615847396907784232501251") );
+        addTest(
+                new BigDecimal("-85070591730234615847396907784232501249"),
+                BigDecimal.valueOf(1),
+                new BigDecimal("-85070591730234615847396907784232501248") );
+        addTest(
+                new BigDecimal("147573952589676412927"),
+                BigDecimal.valueOf(Integer.MAX_VALUE),
+                new BigDecimal("147573952591823896574") );
+        addTest(
+                new BigDecimal("-147573952589676412927"),
+                BigDecimal.valueOf(Integer.MAX_VALUE),
+                new BigDecimal("-147573952587528929280") );
+        addTest(
+                new BigDecimal("79228162514264337593543950335"),
+                BigDecimal.valueOf(999),
+                new BigDecimal("79228162514264337593543951334") );
+        addTest(
+                new BigDecimal("79228162514264337593543950335"),
+                BigDecimal.valueOf(Integer.MAX_VALUE/2),
+                new BigDecimal("79228162514264337594617692158") );
+        addTest(
+                new BigDecimal("79228162514264337593543950335"),
+                BigDecimal.valueOf(Integer.MIN_VALUE/2),
+                new BigDecimal("79228162514264337592470208511") );
+        addTest(
+                new BigDecimal("-79228162514264337593543950335"),
+                BigDecimal.valueOf(Integer.MAX_VALUE/2),
+                new BigDecimal("-79228162514264337592470208512") );
+        addTest(
+                new BigDecimal("79228162514264337593543950335"),
+                BigDecimal.valueOf(-(Integer.MIN_VALUE/2)),
+                new BigDecimal("79228162514264337594617692159") );
+        addTest(
+                new BigDecimal("79228162514264337593543950335"),
+                BigDecimal.valueOf(Long.MAX_VALUE/2),
+                new BigDecimal("79228162518876023611971338238") );
+        addTest(
+                new BigDecimal("79228162514264337593543950335"),
+                BigDecimal.valueOf(Long.MIN_VALUE/2),
+                new BigDecimal("79228162509652651575116562431") );
+        addTest(
+                new BigDecimal("-79228162514264337593543950335"),
+                BigDecimal.valueOf(Long.MAX_VALUE/2),
+                new BigDecimal("-79228162509652651575116562432") );
+        addTest(
+                new BigDecimal("79228162514264337593543950335"),
+                BigDecimal.valueOf(-(Long.MIN_VALUE/2)),
+                new BigDecimal("79228162518876023611971338239") );
+        addTest(
+                new BigDecimal("-9223372036854775808"),
+                BigDecimal.valueOf(1),
+                new BigDecimal("-9223372036854775807") );
+        addTest(
+                new BigDecimal("-9223372036854775808"),
+                BigDecimal.valueOf(Long.MAX_VALUE/2),
+                new BigDecimal("-4611686018427387905") );
+        addTest(
+                new BigDecimal("9223372036854775808"),
+                BigDecimal.valueOf(-1),
+                new BigDecimal("9223372036854775807") );
+        addTest(
+                new BigDecimal("9223372036854775808"),
+                BigDecimal.valueOf(-Long.MAX_VALUE/2),
+                new BigDecimal("4611686018427387905") );
+    }
+
+    private static void testRoundingFromBigInteger(BigInteger bi, int scale, MathContext mc) {
+        BigDecimal bd1 = new BigDecimal(bi,scale, mc);
+        BigDecimal bd2 = (new BigDecimal(bi,scale)).round(mc);
+        Assert.assertEquals(bd1, bd2, "new BigDecimal(BigInteger,int,MathContext):" +
+                    "BigInteger == " +
+                    bi + ";  scale == " + scale + "; result == " +
+                    bd1 + "; expected  == " +
+                    bd2
+            );
+    }
+
+    @Test
+    public void roundingConstructorTest() {
+        testRoundingFromBigInteger(
+                new BigInteger("85070591730234615847396907784232501249"),
+                7, MathContext.DECIMAL64);
+        testRoundingFromBigInteger(
+                new BigInteger("85070591730234615847396907784232501249"),
+                0, MathContext.DECIMAL64);
+        testRoundingFromBigInteger(
+                new BigInteger("85070591730234615847396907784232501249"),
+                -7, MathContext.DECIMAL64);
+        testRoundingFromBigInteger(
+                new BigInteger("85070591730234615847396907784232501249"),
+                7, MathContext.DECIMAL128);
+        testRoundingFromBigInteger(
+                new BigInteger("85070591730234615847396907784232501249"),
+                177, MathContext.DECIMAL128);
+        testRoundingFromBigInteger(
+                new BigInteger("85070591730234615847396907784232501249"),
+                177, MathContext.DECIMAL32);
+        testRoundingFromBigInteger(
+                new BigInteger("85070591730234615847396907784232501249"),
+                177, MathContext.UNLIMITED);
+        testRoundingFromBigInteger(
+                new BigInteger("85070591730234615847396907784232501249"),
+                0, MathContext.UNLIMITED);
+    }
+
+    private static void minLongConstructorTest(MathContext mc) {
+        BigDecimal bd1 = new BigDecimal(Long.MIN_VALUE,mc);
+        BigDecimal bd2 = new BigDecimal(Long.MIN_VALUE).round(mc);
+        Assert.assertEquals(bd1, bd2, "new BigDecimal(long,MathContext):" +
+                    "long == " +
+                    Long.MIN_VALUE + "; result == " +
+                    bd1 + "; expected  == " +
+                    bd2
+            );
+    }
+
+    @Test
+    public void minLongConstructorTest() {
+        minLongConstructorTest(MathContext.UNLIMITED);
+        minLongConstructorTest(MathContext.DECIMAL32);
+        minLongConstructorTest(MathContext.DECIMAL64);
+        minLongConstructorTest(MathContext.DECIMAL128);
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/RoundingTests.java b/ojluni/src/test/java/math/BigDecimal/RoundingTests.java
new file mode 100644
index 0000000..1b4f258
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/RoundingTests.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2005, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6334849
+ * @summary Tests of dropping digits near the scale threshold
+ * @author Joseph D. Darcy
+ */
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class RoundingTests {
+
+    @Test
+    public void roundingTests() {
+        BigDecimal bd1 = BigDecimal.valueOf(11, Integer.MIN_VALUE);
+        BigDecimal bd2 = null;
+        MathContext mc = new MathContext(1);
+        try {
+                bd2 = bd1.round(mc); // should overflow here
+                Assert.fail(String.format("Did not get expected overflow rounding %s to %d digits, got %s%n",
+                                   bd1, mc.getPrecision(), bd2));
+        } catch(ArithmeticException e) {
+            ; // expected
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/ScaleByPowerOfTenTests.java b/ojluni/src/test/java/math/BigDecimal/ScaleByPowerOfTenTests.java
new file mode 100644
index 0000000..d70dcb0
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/ScaleByPowerOfTenTests.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4899722
+ * @summary Basic tests of scaleByPowerOfTen
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class ScaleByPowerOfTenTests {
+
+    @Test
+    public void testScaleByPowerOfTen() {
+        for (int i = -10; i < 10; i++) {
+            BigDecimal bd = BigDecimal.ONE.scaleByPowerOfTen(i);
+            BigDecimal expected;
+
+            expected = new BigDecimal(BigInteger.ONE, -i);
+            Assert.assertEquals(bd, expected, "Unexpected result " +
+                                           bd.toString() +
+                                           "; expected " +
+                                           expected);
+
+            bd = BigDecimal.ONE.negate().scaleByPowerOfTen(i);
+            expected = new BigDecimal(BigInteger.ONE.negate(), -i);
+            Assert.assertEquals(bd, expected, "Unexpected result " +
+                                           bd.toString() +
+                                           "; expected " +
+                                           expected);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/SerializationTests.java b/ojluni/src/test/java/math/BigDecimal/SerializationTests.java
new file mode 100644
index 0000000..d6b6499
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/SerializationTests.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6177836
+ * @summary Verify BigDecimal objects with collapsed values are serialized properly.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import java.io.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class SerializationTests {
+
+    static void checkSerialForm(BigDecimal bd) throws Exception {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(bd);
+        oos.flush();
+        oos.close();
+        ObjectInputStream ois = new
+            ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
+        BigDecimal tmp = (BigDecimal)ois.readObject();
+
+        if (!bd.equals(tmp) || bd.hashCode() != tmp.hashCode()) {
+            Assert.fail("  original : " + bd +
+                " (hash: 0x" + Integer.toHexString(bd.hashCode()) + ")" +
+                " serialized : " + tmp +
+                " (hash: 0x" + Integer.toHexString(tmp.hashCode()) + ")");
+        }
+    }
+
+    @Test
+    public void testSerialization() throws Exception {
+        BigDecimal values[] = {
+            BigDecimal.ZERO,
+            BigDecimal.ONE,
+            BigDecimal.TEN,
+            new BigDecimal(0),
+            new BigDecimal(1),
+            new BigDecimal(10),
+            new BigDecimal(Integer.MAX_VALUE),
+            new BigDecimal(Long.MAX_VALUE-1),
+            new BigDecimal(BigInteger.valueOf(1), 1),
+            new BigDecimal(BigInteger.valueOf(100), 50),
+        };
+
+        for(BigDecimal value : values) {
+            checkSerialForm(value);
+            checkSerialForm(value.negate());
+        }
+
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/SquareRootTests.java b/ojluni/src/test/java/math/BigDecimal/SquareRootTests.java
new file mode 100644
index 0000000..27b1013
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/SquareRootTests.java
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4851777
+ * @summary Tests of BigDecimal.sqrt().
+ */
+
+import java.math.*;
+import java.util.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class SquareRootTests {
+
+    @Test
+    public void negativeTests() {
+        for (long i = -10; i < 0; i++) {
+            for (int j = -5; j < 5; j++) {
+                try {
+                    BigDecimal input = BigDecimal.valueOf(i, j);
+                    BigDecimal result = input.sqrt(MathContext.DECIMAL64);
+                    Assert.fail("Unexpected sqrt of negative: (" +
+                                       input + ").sqrt()  = " + result );
+                } catch (ArithmeticException e) {
+                    ; // Expected
+                }
+            }
+        }
+    }
+
+    @Test
+    public void zeroTests() {
+        for (int i = -100; i < 100; i++) {
+            BigDecimal expected = BigDecimal.valueOf(0L, i/2);
+            // These results are independent of rounding mode
+            compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.UNLIMITED),
+                                expected, true, "zeros");
+
+            compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.DECIMAL64),
+                                expected, true, "zeros");
+        }
+    }
+
+    /**
+     * sqrt(10^2N) is 10^N
+     * Both numerical value and representation should be verified
+     */
+    @Test
+    public void evenPowersOfTenTests() {
+        MathContext oneDigitExactly = new MathContext(1, RoundingMode.UNNECESSARY);
+
+        for (int scale = -100; scale <= 100; scale++) {
+            BigDecimal testValue       = BigDecimal.valueOf(1, 2*scale);
+            BigDecimal expectedNumericalResult = BigDecimal.valueOf(1, scale);
+
+            BigDecimal result;
+
+
+            equalNumerically(expectedNumericalResult,
+                                           result = testValue.sqrt(MathContext.DECIMAL64),
+                                           "Even powers of 10, DECIMAL64");
+
+            // Can round to one digit of precision exactly
+            equalNumerically(expectedNumericalResult,
+                                           result = testValue.sqrt(oneDigitExactly),
+                                           "even powers of 10, 1 digit");
+            if (result.precision() > 1) {
+                Assert.fail("Excess precision for " + result);
+            }
+            // If rounding to more than one digit, do precision / scale checking...
+        }
+    }
+
+    @Test
+    public void squareRootTwoTests() {
+        BigDecimal TWO = new BigDecimal(2);
+
+        // Square root of 2 truncated to 65 digits
+        BigDecimal highPrecisionRoot2 =
+            new BigDecimal("1.41421356237309504880168872420969807856967187537694807317667973799");
+
+
+        RoundingMode[] modes = {
+            RoundingMode.UP,       RoundingMode.DOWN,
+            RoundingMode.CEILING, RoundingMode.FLOOR,
+            RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN
+        };
+
+        // For each interesting rounding mode, for precisions 1 to, say
+        // 63 numerically compare TWO.sqrt(mc) to
+        // highPrecisionRoot2.round(mc)
+
+        for (RoundingMode mode : modes) {
+            for (int precision = 1; precision < 63; precision++) {
+                MathContext mc = new MathContext(precision, mode);
+                BigDecimal expected = highPrecisionRoot2.round(mc);
+                BigDecimal computed = TWO.sqrt(mc);
+
+                equalNumerically(expected, computed, "sqrt(2)");
+            }
+        }
+    }
+
+    @Test
+    public void lowPrecisionPerfectSquares() {
+        // For 5^2 through 9^2, if the input is rounded to one digit
+        // first before the root is computed, the wrong answer will
+        // result. Verify results and scale for different rounding
+        // modes and precisions.
+        long[][] squaresWithOneDigitRoot = {{ 4, 2},
+                                            { 9, 3},
+                                            {25, 5},
+                                            {36, 6},
+                                            {49, 7},
+                                            {64, 8},
+                                            {81, 9}};
+
+        for (long[] squareAndRoot : squaresWithOneDigitRoot) {
+            BigDecimal square     = new BigDecimal(squareAndRoot[0]);
+            BigDecimal expected   = new BigDecimal(squareAndRoot[1]);
+
+            for (int scale = 0; scale <= 4; scale++) {
+                BigDecimal scaledSquare = square.setScale(scale, RoundingMode.UNNECESSARY);
+                int expectedScale = scale/2;
+                for (int precision = 0; precision <= 5; precision++) {
+                    for (RoundingMode rm : RoundingMode.values()) {
+                        MathContext mc = new MathContext(precision, rm);
+                        BigDecimal computedRoot = scaledSquare.sqrt(mc);
+
+                        equalNumerically(expected, computedRoot, "simple squares");
+
+                        int computedScale = computedRoot.scale();
+                        if (precision >=  expectedScale + 1 && computedScale != expectedScale) {
+                            Assert.fail(String.format("%s\tprecision=%d\trm=%s%n",
+                                          computedRoot, precision, rm) +
+                                        String.format("\t%s does not have expected scale of %d%n.",
+                                              computedRoot, expectedScale));
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private static void compare(BigDecimal a, BigDecimal b, boolean expected, String prefix) {
+        boolean result = a.equals(b);
+        Assert.assertEquals(result, expected, "Testing " + prefix +
+                               "(" + a + ").compareTo(" + b + ") => " + result +
+                               "\n\tExpected " + expected);
+    }
+
+    private static void equalNumerically(BigDecimal a, BigDecimal b, String prefix) {
+        compareNumerically(a, b, 0, prefix);
+    }
+
+    private static void compareNumerically(BigDecimal a, BigDecimal b,
+                                          int expected, String prefix) {
+        int result = a.compareTo(b);
+        Assert.assertEquals(result, expected, "Testing " + prefix +
+                               "(" + a + ").compareTo(" + b + ") => " + result +
+                               "\n\tExpected " + expected);
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/StringConstructor.java b/ojluni/src/test/java/math/BigDecimal/StringConstructor.java
new file mode 100644
index 0000000..a4f6dc6
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/StringConstructor.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1999, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main StringConstructor
+ * @bug 4103117 4331084 4488017 4490929 6255285 6268365 8074460 8078672
+ * @summary Tests the BigDecimal string constructor (use -Dseed=X to set PRNG seed).
+ * @key randomness
+ */
+
+import java.math.*;
+import java.util.Random;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class StringConstructor {
+
+    @Test
+    public void testBadStrings() {
+        constructWithError("");
+        constructWithError("+");
+        constructWithError("-");
+        constructWithError("+e");
+        constructWithError("-e");
+        constructWithError("e+");
+        constructWithError("1.-0");
+        constructWithError(".-123");
+        constructWithError("-");
+        constructWithError("--1.1");
+        constructWithError("-+1.1");
+        constructWithError("+-1.1");
+        constructWithError("1-.1");
+        constructWithError("1+.1");
+        constructWithError("1.111+1");
+        constructWithError("1.111-1");
+        constructWithError("11.e+");
+        constructWithError("11.e-");
+        constructWithError("11.e+-");
+        constructWithError("11.e-+");
+        constructWithError("11.e-+1");
+        constructWithError("11.e+-1");
+
+        // Range checks
+        constructWithError("1e" + Integer.MIN_VALUE);
+        constructWithError("10e" + Integer.MIN_VALUE);
+        constructWithError("0.01e" + Integer.MIN_VALUE);
+        constructWithError("1e" + ((long) Integer.MIN_VALUE - 1));
+        constructWithError("1e" + ((long) Integer.MAX_VALUE + 1));
+    }
+
+    @Test
+    public void testRoundtrip() {
+        // Roundtrip tests
+        Random random = new Random();
+        for (int i=0; i<100; i++) {
+            int size = random.nextInt(100) + 1;
+            BigInteger bi = new BigInteger(size, random);
+            if (random.nextBoolean())
+                bi = bi.negate();
+            int decimalLength = bi.toString().length();
+            int scale = random.nextInt(decimalLength);
+            BigDecimal bd = new BigDecimal(bi, scale);
+            String bdString = bd.toString();
+            BigDecimal bdDoppel = new BigDecimal(bdString);
+            Assert.assertEquals(bd, bdDoppel, "bd string: scale: " + bd.scale() +
+                                   "\t" + bdString + "\nbd doppel: scale: " + bdDoppel.scale() +
+                                   "\t" + bdDoppel.toString());
+        }
+    }
+
+    /*
+     * Verify precision is set properly if the significand has
+     * non-ASCII leading zeros.
+     */
+    @Test
+    public void nonAsciiZeroTest() {
+        String[] values = {
+            "00004e5",
+            "\u0660\u0660\u0660\u06604e5",
+        };
+
+        BigDecimal expected = new BigDecimal("4e5");
+
+        for(String s : values) {
+            BigDecimal tmp = new BigDecimal(s);
+            Assert.assertFalse(! expected.equals(tmp) || tmp.precision() != 1,
+                "Bad conversion of " + s + "got " +
+                                   tmp + "precision = " + tmp.precision());
+        }
+
+    }
+
+    @Test
+    public void testLeadingExponentZeroTest() {
+        BigDecimal twelve = new BigDecimal("12");
+        BigDecimal onePointTwo = new BigDecimal("1.2");
+
+        String start = "1.2e0";
+        String end = "1";
+        String middle = "";
+
+        // Test with more excess zeros than the largest number of
+        // decimal digits needed to represent a long
+        int limit  = ((int)Math.log10(Long.MAX_VALUE)) + 6;
+        for(int i = 0; i < limit; i++, middle += "0") {
+            String t1 = start + middle;
+            String t2 = t1 + end;
+
+            testString(t1, onePointTwo);
+            testString(t2, twelve);
+        }
+    }
+
+    private static void testString(String s, BigDecimal expected) {
+        testString0(s, expected);
+        testString0(switchZero(s), expected);
+    }
+
+    private static void testString0(String s, BigDecimal expected) {
+        Assert.assertEquals(new BigDecimal(s), expected, s + " is not equal to " + expected);
+    }
+
+    private static String switchZero(String s) {
+        return s.replace('0', '\u0660'); // Arabic-Indic zero
+    }
+
+    private static void constructWithError(String badString) {
+        try {
+            BigDecimal d = new BigDecimal(badString);
+            Assert.fail(badString + " accepted");
+        } catch(NumberFormatException e) {
+            // expected
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/StrippingZerosTest.java b/ojluni/src/test/java/math/BigDecimal/StrippingZerosTest.java
new file mode 100644
index 0000000..93084fd
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/StrippingZerosTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4108852
+ * @summary A few tests of stripTrailingZeros
+ * @run main StrippingZerosTest
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 StrippingZerosTest
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class StrippingZerosTest {
+
+    @Test
+    public void testStrippingZeros() {
+        BigDecimal [][] testCases = {
+            {new BigDecimal("1.00000"),         new BigDecimal("1")},
+            {new BigDecimal("1.000"),           new BigDecimal("1")},
+            {new BigDecimal("1"),               new BigDecimal("1")},
+            {new BigDecimal("0.1234"),          new BigDecimal("0.1234")},
+            {new BigDecimal("0.12340"),         new BigDecimal("0.1234")},
+            {new BigDecimal("0.12340000000"),   new BigDecimal("0.1234")},
+            {new BigDecimal("1234.5678"),       new BigDecimal("1234.5678")},
+            {new BigDecimal("1234.56780"),      new BigDecimal("1234.5678")},
+            {new BigDecimal("1234.567800000"),  new BigDecimal("1234.5678")},
+            {new BigDecimal("0"),               new BigDecimal("0")},
+            {new BigDecimal("0e2"),             BigDecimal.ZERO},
+            {new BigDecimal("0e-2"),            BigDecimal.ZERO},
+            {new BigDecimal("0e42"),            BigDecimal.ZERO},
+            {new BigDecimal("+0e42"),           BigDecimal.ZERO},
+            {new BigDecimal("-0e42"),           BigDecimal.ZERO},
+            {new BigDecimal("0e-42"),           BigDecimal.ZERO},
+            {new BigDecimal("+0e-42"),          BigDecimal.ZERO},
+            {new BigDecimal("-0e-42"),          BigDecimal.ZERO},
+            {new BigDecimal("0e-2"),            BigDecimal.ZERO},
+            {new BigDecimal("0e100"),           BigDecimal.ZERO},
+            {new BigDecimal("0e-100"),          BigDecimal.ZERO},
+            {new BigDecimal("10"),              new BigDecimal("1e1")},
+            {new BigDecimal("20"),              new BigDecimal("2e1")},
+            {new BigDecimal("100"),             new BigDecimal("1e2")},
+            {new BigDecimal("1000000000"),      new BigDecimal("1e9")},
+            {new BigDecimal("100000000e1"),     new BigDecimal("1e9")},
+            {new BigDecimal("10000000e2"),      new BigDecimal("1e9")},
+            {new BigDecimal("1000000e3"),       new BigDecimal("1e9")},
+            {new BigDecimal("100000e4"),        new BigDecimal("1e9")},
+            // BD value which larger than Long.MaxValue
+            {new BigDecimal("1.0000000000000000000000000000"),    new BigDecimal("1")},
+            {new BigDecimal("-1.0000000000000000000000000000"),   new BigDecimal("-1")},
+            {new BigDecimal("1.00000000000000000000000000001"),   new BigDecimal("1.00000000000000000000000000001")},
+            {new BigDecimal("1000000000000000000000000000000e4"), new BigDecimal("1e34")},
+        };
+
+        for(int i = 0; i < testCases.length; i++) {
+
+            BigDecimal stripped = testCases[i][0].stripTrailingZeros();
+            Assert.assertEquals(stripped, testCases[i][1],
+                "For input " + testCases[i][0].toString() +
+                           " did not received expected result " +
+                           testCases[i][1].toString() + ",  got " +
+                           testCases[i][0].stripTrailingZeros());
+
+            testCases[i][0] = testCases[i][0].negate();
+            testCases[i][1] = testCases[i][1].negate();
+
+            stripped = testCases[i][0].stripTrailingZeros();
+            Assert.assertEquals(stripped, testCases[i][1],
+                "For input " + testCases[i][0].toString() +
+                           " did not received expected result " +
+                           testCases[i][1].toString() + ",  got " +
+                           testCases[i][0].stripTrailingZeros());
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/ToPlainStringTests.java b/ojluni/src/test/java/math/BigDecimal/ToPlainStringTests.java
new file mode 100644
index 0000000..54a70af
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/ToPlainStringTests.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2004, 2018, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4984872
+ * @summary Basic tests of toPlainString method
+ * @run main ToPlainStringTests
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 ToPlainStringTests
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class ToPlainStringTests {
+
+    @Test
+    public void testToPlainString() {
+        String [][] testCases = {
+            {"0",                       "0"},
+            {"1",                       "1"},
+            {"10",                      "10"},
+            {"2e1",                     "20"},
+            {"3e2",                     "300"},
+            {"4e3",                     "4000"},
+            {"5e4",                     "50000"},
+            {"6e5",                     "600000"},
+            {"7e6",                     "7000000"},
+            {"8e7",                     "80000000"},
+            {"9e8",                     "900000000"},
+            {"1e9",                     "1000000000"},
+
+            {".0",                      "0.0"},
+            {".1",                      "0.1"},
+            {".10",                     "0.10"},
+            {"1e-1",                    "0.1"},
+            {"1e-1",                    "0.1"},
+            {"2e-2",                    "0.02"},
+            {"3e-3",                    "0.003"},
+            {"4e-4",                    "0.0004"},
+            {"5e-5",                    "0.00005"},
+            {"6e-6",                    "0.000006"},
+            {"7e-7",                    "0.0000007"},
+            {"8e-8",                    "0.00000008"},
+            {"9e-9",                    "0.000000009"},
+            {"9000e-12",                "0.000000009000"},
+
+            {"9000e-22",                 "0.0000000000000000009000"},
+            {"12345678901234567890",     "12345678901234567890"},
+            {"12345678901234567890e22",  "123456789012345678900000000000000000000000"},
+            {"12345678901234567890e-22", "0.0012345678901234567890"},
+        };
+
+        for(String[] testCase: testCases) {
+            BigDecimal bd = new BigDecimal(testCase[0]);
+            String s;
+
+            s = bd.toPlainString();
+            Assert.assertEquals(s, testCase[1],
+                "Unexpected plain result ``" + s + "'' from BigDecimal " + bd);
+
+            bd = new BigDecimal("-"+testCase[0]);
+            s = bd.toPlainString();
+            Assert.assertFalse(bd.signum()!=0 && !s.equals("-"+testCase[1]),
+                "Unexpected plain result ``" + s + "'' from BigDecimal " + bd);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/ZeroScalingTests.java b/ojluni/src/test/java/math/BigDecimal/ZeroScalingTests.java
new file mode 100644
index 0000000..742abc3
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/ZeroScalingTests.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4902952 4905407 4916149 8057793
+ * @summary Tests that the scale of zero is propagated properly and has the
+ * proper effect and that setting the scale to zero does not mutate the
+ * BigDecimal.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import java.util.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class ZeroScalingTests {
+
+    static MathContext longEnough = new MathContext(50, RoundingMode.UNNECESSARY);
+
+    static BigDecimal[]  zeros = new BigDecimal[23];
+    static {
+        for(int i = 0; i < 21; i++) {
+            zeros[i] = new BigDecimal(BigInteger.ZERO, i-10);
+        }
+        zeros[21] = new BigDecimal(BigInteger.ZERO, Integer.MIN_VALUE);
+        zeros[22] = new BigDecimal(BigInteger.ZERO, Integer.MAX_VALUE);
+    }
+
+    static BigDecimal element = BigDecimal.valueOf(100, -2);
+
+    static MathContext[] contexts = {
+        new MathContext(0, RoundingMode.UNNECESSARY),
+        new MathContext(100, RoundingMode.UNNECESSARY),
+        new MathContext(5, RoundingMode.UNNECESSARY),
+        new MathContext(4, RoundingMode.UNNECESSARY),
+        new MathContext(3, RoundingMode.UNNECESSARY),
+        new MathContext(2, RoundingMode.UNNECESSARY),
+        new MathContext(1, RoundingMode.UNNECESSARY),
+    };
+
+
+    @Test
+    public void addTests() {
+        for(BigDecimal zero1: zeros) {
+            for(BigDecimal zero2: zeros) {
+                BigDecimal expected = new BigDecimal(BigInteger.ZERO,
+                                                     Math.max(zero1.scale(), zero2.scale()));
+                BigDecimal result = zero1.add(zero2);
+
+                Assert.assertEquals(result, expected, "For classic exact add, expected scale of " +
+                           expected.scale() + "; got " +
+                           result.scale() + ".");
+
+                result = zero1.add(zero2, MathContext.UNLIMITED);
+                Assert.assertEquals(result, expected, "For UNLIMITED math context add," +
+                           " expected scale of " +
+                           expected.scale() + "; got " +
+                           result.scale() + ".");
+
+                result = zero1.add(zero2, longEnough);
+                Assert.assertEquals(result, expected, "For longEnough math context add," +
+                           " expected scale of " +
+                           expected.scale() + "; got " +
+                           result.scale() + ".");
+            }
+        }
+
+        // Test effect of adding zero to a nonzero value.
+        for (MathContext mc: contexts) {
+            for (BigDecimal zero: zeros) {
+                if (Math.abs((long)zero.scale()) < 100 ) {
+
+                    int preferredScale = Math.max(zero.scale(), element.scale());
+                    if (mc.getPrecision() != 0) {
+                        if (preferredScale < -4 )
+                            preferredScale = -4;
+                        else if (preferredScale > -(5 - mc.getPrecision())) {
+                            preferredScale = -(5 - mc.getPrecision());
+                        }
+                    }
+
+                    BigDecimal result = element.add(zero, mc);
+                    Assert.assertFalse(result.scale() != preferredScale ||
+                            result.compareTo(element) != 0,
+                        "Expected scale  " + preferredScale +
+                               " result scale was " + result.scale() +
+                               " ; value was " + result);
+
+                    result = zero.add(element, mc);
+                    Assert.assertFalse(result.scale() != preferredScale ||
+                            result.compareTo(element) != 0,
+                        "Expected scale  " + preferredScale +
+                                   " result scale was " + result.scale() +
+                                   " ; value was " + result);
+
+                    result = element.negate().add(zero, mc);
+                    Assert.assertFalse(result.scale() != preferredScale ||
+                            result.compareTo(element.negate()) != 0,
+                        "Expected scale  " + preferredScale +
+                                   " result scale was " + result.scale() +
+                                   " ; value was " + result);
+
+                    result = zero.add(element.negate(), mc);
+                    Assert.assertFalse(result.scale() != preferredScale ||
+                            result.compareTo(element.negate()) != 0,
+                        "Expected scale  " + preferredScale +
+                                   " result scale was " + result.scale() +
+                                   " ; value was " + result);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void subtractTests() {
+        for(BigDecimal zero1: zeros) {
+            for(BigDecimal zero2: zeros) {
+                BigDecimal expected = new BigDecimal(BigInteger.ZERO,
+                                                     Math.max(zero1.scale(), zero2.scale()));
+                BigDecimal result = zero1.subtract(zero2);
+
+                Assert.assertEquals(result, expected,
+                    "For classic exact subtract, expected scale of " +
+                               expected.scale() + "; got " +
+                               result.scale() + ".");
+
+                result = zero1.subtract(zero2, MathContext.UNLIMITED);
+                Assert.assertEquals(result, expected, "For UNLIMITED math context subtract," +
+                           " expected scale of " +
+                           expected.scale() + "; got " +
+                           result.scale() + ".");
+
+                result = zero1.subtract(zero2, longEnough);
+                Assert.assertEquals(result, expected, "For longEnough math context subtract," +
+                           " expected scale of " +
+                           expected.scale() + "; got " +
+                           result.scale() + ".");
+            }
+        }
+
+
+        // Test effect of adding zero to a nonzero value.
+        for (MathContext mc: contexts) {
+            for (BigDecimal zero: zeros) {
+                if (Math.abs((long)zero.scale()) < 100 ) {
+
+                    int preferredScale = Math.max(zero.scale(), element.scale());
+                    if (mc.getPrecision() != 0) {
+                        if (preferredScale < -4 )
+                            preferredScale = -4;
+                        else if (preferredScale > -(5 - mc.getPrecision())) {
+                            preferredScale = -(5 - mc.getPrecision());
+                        }
+                    }
+
+                    BigDecimal result = element.subtract(zero, mc);
+                    Assert.assertFalse(result.scale() != preferredScale ||
+                            result.compareTo(element) != 0,
+                        "Expected scale  " + preferredScale +
+                                           " result scale was " + result.scale() +
+                                           " ; value was " + result);
+
+                    result = zero.subtract(element, mc);
+                    Assert.assertFalse(result.scale() != preferredScale ||
+                            result.compareTo(element.negate()) != 0,
+                        "Expected scale  " + preferredScale +
+                                   " result scale was " + result.scale() +
+                                   " ; value was " + result);
+
+                    result = element.negate().subtract(zero, mc);
+                    Assert.assertFalse(result.scale() != preferredScale ||
+                            result.compareTo(element.negate()) != 0,
+                        "Expected scale  " + preferredScale +
+                                   " result scale was " + result.scale() +
+                                   " ; value was " + result);
+
+                    result = zero.subtract(element.negate(), mc);
+                    Assert.assertFalse(result.scale() != preferredScale ||
+                            result.compareTo(element) != 0,
+                        "Expected scale  " + preferredScale +
+                                   " result scale was " + result.scale() +
+                                   " ; value was " + result);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void multiplyTests() {
+        BigDecimal[] ones = {
+            BigDecimal.valueOf(1, 0),
+            BigDecimal.valueOf(10, 1),
+            BigDecimal.valueOf(1000, 3),
+            BigDecimal.valueOf(100000000, 8),
+        };
+
+        List<BigDecimal> values = new LinkedList<BigDecimal>();
+        values.addAll(Arrays.asList(zeros));
+        values.addAll(Arrays.asList(ones));
+
+        for(BigDecimal zero1: zeros) {
+            for(BigDecimal value: values) {
+                BigDecimal expected = new BigDecimal(BigInteger.ZERO,
+                                                     (int)Math.min(Math.max((long)zero1.scale()+value.scale(),
+                                                                            Integer.MIN_VALUE ),
+                                                                   Integer.MAX_VALUE ) );
+                BigDecimal result = zero1.multiply(value);
+
+                Assert.assertEquals(result, expected,
+                    "For classic exact multiply, expected scale of " +
+                               expected.scale() + "; got " +
+                               result.scale() + ".");
+
+                result = zero1.multiply(value, MathContext.UNLIMITED);
+                Assert.assertEquals(result, expected, "For UNLIMITED math context multiply," +
+                                       " expected scale of " +
+                                       expected.scale() + "; got " +
+                                       result.scale() + ".");
+
+                result = zero1.multiply(value, longEnough);
+                Assert.assertEquals(result, expected, "For longEnough math context multiply," +
+                           " expected scale of " +
+                           expected.scale() + "; got " +
+                           result.scale() + ".");
+            }
+        }
+    }
+
+    @Test
+    public void divideTests() {
+        BigDecimal [] ones = {
+            BigDecimal.valueOf(1, 0),
+            BigDecimal.valueOf(10, -1),
+            BigDecimal.valueOf(100, -2),
+            BigDecimal.valueOf(1000, -3),
+            BigDecimal.valueOf(1000000, -5),
+        };
+
+        for(BigDecimal one: ones) {
+            for(BigDecimal zero: zeros) {
+                BigDecimal expected = new BigDecimal(BigInteger.ZERO,
+                                                     (int)Math.min(Math.max((long)zero.scale() - one.scale(),
+                                                                            Integer.MIN_VALUE ),
+                                                                   Integer.MAX_VALUE ) );
+                BigDecimal result = zero.divide(one);
+
+                Assert.assertEquals(result, expected, "For classic exact divide, expected scale of " +
+                               expected.scale() + "; got " +
+                               result.scale() + ".");
+
+                result = zero.divide(one, MathContext.UNLIMITED);
+                Assert.assertEquals(result, expected, "For UNLIMITED math context divide," +
+                               " expected scale of " +
+                               expected.scale() + "; got " +
+                               result.scale() + ".");
+
+                result = zero.divide(one, longEnough);
+                Assert.assertEquals(result, expected, "For longEnough math context divide," +
+                               " expected scale of " +
+                               expected.scale() + "; got " +
+                               result.scale() + ".");
+            }
+        }
+    }
+
+    @Test
+    public void setScaleTests() {
+        int[] scales = {
+            Integer.MIN_VALUE,
+            Integer.MIN_VALUE+1,
+            -10000000,
+            -3,
+            -2,
+            -1,
+            0,
+            1,
+            2,
+            3,
+            10,
+            10000000,
+            Integer.MAX_VALUE-1,
+            Integer.MAX_VALUE
+        };
+
+        for(BigDecimal zero: zeros) {
+            for(int scale: scales) {
+                try {
+                    BigDecimal bd = zero.setScale(scale);
+                }
+                catch (ArithmeticException e) {
+                    Assert.fail("Exception when trying to set a scale of " + scale + " on " + zero);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void toEngineeringStringTests() {
+        String [][] testCases  = {
+            {"0E+10",   "0.00E+12"},
+            {"0E+9",    "0E+9"},
+            {"0E+8",    "0.0E+9"},
+            {"0E+7",    "0.00E+9"},
+
+            {"0E-10",   "0.0E-9"},
+            {"0E-9",    "0E-9"},
+            {"0E-8",    "0.00E-6"},
+            {"0E-7",    "0.0E-6"},
+        };
+
+        for(String[] testCase: testCases) {
+            BigDecimal bd = new BigDecimal(testCase[0]);
+            String result = bd.toEngineeringString();
+
+            Assert.assertFalse(!result.equals(testCase[1]) || !bd.equals(new BigDecimal(result)),
+                "From input ``" + testCase[0] + ",'' " +
+                           " bad engineering string output ``" + result +
+                           "''; expected ``" + testCase[1] + ".''");
+        }
+    }
+
+    @Test
+    public void ulpTests() {
+        for(BigDecimal zero: zeros) {
+            BigDecimal result;
+            BigDecimal expected = BigDecimal.valueOf(1, zero.scale());
+
+            result = zero.ulp();
+            Assert.assertEquals(result, expected, "Unexpected ulp value for zero value " +
+                       zero + "; expected " + expected +
+                       ", got " + result);
+        }
+    }
+
+    @Test
+    public void setScaleDoesNotMutateTest() {
+        BigDecimal total = new BigDecimal("258815507198903607775511093103396443816569106750031264155319238473795838680758514810110764742309284477206138527975952150289602995045050194333030191178778772026538699925775139201970526695485362661420908248887297829319881475178467494779683293036572059595504702727301324759997409522995072582369210284334718757260859794972695026582432867589093687280300148141501712013226636373167978223780290547640482160818746599330924736802844173226042389174403401903999447463440670236056324929325189403433689"
+                + ".426167432065785331444814035799717606745777287606858873045971898862329763544687891847664736523584843544347118836628373041412918374550458884706686730726101338872517021688769782894793734049819222924171842793485919753186993388451909096042127903835765393729547730953942175461146061715108701615615142134282261293656760570061554783195726716403304101469782303957325142638493327692352838806741611887655695029948975509680496573999174402058593454203190963443179532640446352828089016874853634851387762579319853267317320515941105912189838719919259277721994880193541634872882180184303434360412344059435559680494807415573269199203376126242271766939666939316648575065702750502798973418978204972336924254702551350654650573582614211506856383897692911422458286912085339575875324832979140870119455620532272318122103640233069115700020760625493816902806241630788230268031695140687964931377988962507263990468276009750998066442971308866347136022907166625330623130307555914930120150437900510530537258665172619821272937026713977709974434967165159545592482710663639966781678268622620229577009317698254134914742098420792313931843709810905414336383757407675429663714210967924767434203021205270369316797752411974617662200898086335322218191674846795163102021505555508444216708745911194321674887527227200297039471799580744303346354057273540730643842091810899490590914195225087593013834388801018488174855060306804024894292757613618190472234110859436472645203753139820658279559340251226992556744343475086923568365637919479462424794554522865559888240039662899509652221329892034706445253487898044421278283079233226845124525434586324657471286953226255430662125870993375281512713207125720748163498642795960457639954616530163959004770092547297392499137383176609646505351001304840762905826237024982330597805063521162285806541220110524989649256399233792799406995068469271941269511818994954109392839548141262324660472253632382325038836831429045617036015122388070240133760858500132713255407855625837956886349324981003917084922808187223285051144454915441134217743066575863563572152133978905444998209075763950909784148142018992367290485890072303179512881131769414783097454103103347826517701720263541869335631166977965013552647906729408522950996105479525445916501155305220090853891226367184989434453290788068397817927893708837722255115237672194162924260945492012622891770365546831236789867922136747819364833843397165107825773447549885351449899330007200651144003961228091210630807333236718793283427788965479074476288255387824982443633190938302785760754436525586544523339170400053128503337395428393881357669568532722167493096151221381017320147344991331421789379785964440840684363041795410525097564979585773948558651896834067324427900848255265001498890329859444233861478388742393060996236783742654761350763876989363052609107226398858310051497856931093693697981165801539060516895227818925342535261227134364063673285588256280386915163875872231395348293505967057794409379709079685798908660258077792158532257603211711587587586356431658240229896344639704");
+
+        Assert.assertEquals(total.setScale(0, RoundingMode.DOWN),
+             total.setScale(0, RoundingMode.DOWN));
+    }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/BigIntegerTest.java b/ojluni/src/test/java/math/BigInteger/BigIntegerTest.java
new file mode 100644
index 0000000..04bc7cf
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/BigIntegerTest.java
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (c) 1998, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main BigIntegerTest
+ * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 8078672 8032027
+ * @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed)
+ * @run main/timeout=400 BigIntegerTest
+ * @author madbot
+ * @key randomness
+ */
+package test.java.math.BigInteger;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Random;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * This is a simple test class created to ensure that the results
+ * generated by BigInteger adhere to certain identities. Passing
+ * this test is a strong assurance that the BigInteger operations
+ * are working correctly.
+ *
+ * Four arguments may be specified which give the number of
+ * decimal digits you desire in the four batches of test numbers.
+ *
+ * The tests are performed on arrays of random numbers which are
+ * generated by a Random class as well as special cases which
+ * throw in boundary numbers such as 0, 1, maximum sized, etc.
+ *
+ */
+
+// Android-changed: Replace error counting with asserts.
+public class BigIntegerTest {
+    //
+    // Bit large number thresholds based on the int thresholds
+    // defined in BigInteger itself:
+    //
+    // KARATSUBA_THRESHOLD        = 80  ints = 2560 bits
+    // TOOM_COOK_THRESHOLD        = 240 ints = 7680 bits
+    // KARATSUBA_SQUARE_THRESHOLD = 128 ints = 4096 bits
+    // TOOM_COOK_SQUARE_THRESHOLD = 216 ints = 6912 bits
+    //
+    // SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 20 ints = 640 bits
+    //
+    // BURNIKEL_ZIEGLER_THRESHOLD = 80  ints = 2560 bits
+    //
+    static final int BITS_KARATSUBA = 2560;
+    static final int BITS_TOOM_COOK = 7680;
+    static final int BITS_KARATSUBA_SQUARE = 4096;
+    static final int BITS_TOOM_COOK_SQUARE = 6912;
+    static final int BITS_SCHOENHAGE_BASE = 640;
+    static final int BITS_BURNIKEL_ZIEGLER = 2560;
+    static final int BITS_BURNIKEL_ZIEGLER_OFFSET = 1280;
+
+    static final int ORDER_SMALL = 60;
+    static final int ORDER_MEDIUM = 100;
+    // #bits for testing Karatsuba
+    static final int ORDER_KARATSUBA = 2760;
+    // #bits for testing Toom-Cook and Burnikel-Ziegler
+    static final int ORDER_TOOM_COOK = 8000;
+    // #bits for testing Karatsuba squaring
+    static final int ORDER_KARATSUBA_SQUARE = 4200;
+    // #bits for testing Toom-Cook squaring
+    static final int ORDER_TOOM_COOK_SQUARE = 7000;
+
+    static final int SIZE = 1000; // numbers per batch
+
+    private static Random random = new Random();
+
+    static boolean failure = false;
+
+    private static void constructor() {
+        // --- guard condition tests for array indexing ---
+
+        int arrayLength = 23;
+        int halfLength = arrayLength/2;
+        byte[] array = new byte[arrayLength];
+        random.nextBytes(array);
+
+        int[][] offLen = new int[][] { // offset, length, num exceptions
+            {-1, arrayLength, 1},                         // negative offset
+            {0, arrayLength, 0},                          // OK
+            {1, arrayLength, 1},                          // length overflow
+            {arrayLength - 1, 1, 0},                      // OK
+            {arrayLength, 1, 1},                          // offset overflow
+            {0, -1, 1},                                   // negative length
+            {halfLength, arrayLength - halfLength + 1, 1} // length overflow
+        };
+
+        // two's complement
+        for (int[] ol : offLen) {
+            try {
+                BigInteger bi = new BigInteger(array, ol[0], ol[1]);
+                if (ol[2] == 1) {
+                    Assert.fail("IndexOutOfBoundsException did not occur for "
+                        + " two's complement constructor with parameters offset "
+                        + ol[0] + " and length " + ol[1]);
+                }
+            } catch (IndexOutOfBoundsException e) {
+                if (ol[2] == 0) {
+                    Assert.fail("Unexpected IndexOutOfBoundsException did occur for "
+                            + " two's complement constructor with parameters offset "
+                            + ol[0] + " and length " + ol[1]);
+                }
+            }
+        }
+
+        // sign-magnitude
+        for (int[] ol : offLen) {
+            try {
+                BigInteger bi = new BigInteger(1, array, ol[0], ol[1]);
+                if (ol[2] == 1) {
+                    Assert.fail("IndexOutOfBoundsException did not occur for "
+                        + " sign-magnitude constructor with parameters offset "
+                        + ol[0] + " and length " + ol[1]);
+                }
+            } catch (IndexOutOfBoundsException e) {
+                if (ol[2] == 0) {
+                    Assert.fail("Unexpected IndexOutOfBoundsException did occur for "
+                            + " two's complement constructor with parameters offset "
+                            + ol[0] + " and length " + ol[1]);
+                }
+            }
+        }
+
+        // --- tests for creation of zero-valued BigIntegers ---
+
+        byte[] magZeroLength = new byte[0];
+        for (int signum = -1; signum <= 1; signum++) {
+            BigInteger bi = new BigInteger(signum, magZeroLength);
+            Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0,
+                    "A: Zero length BigInteger != 0 for signum " + signum);
+        }
+
+        for (int signum = -1; signum <= 1; signum++) {
+            BigInteger bi = new BigInteger(signum, magZeroLength, 0, 0);
+            Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0,
+                    "B: Zero length BigInteger != 0 for signum " + signum);
+        }
+
+        byte[] magNonZeroLength = new byte[42];
+        random.nextBytes(magNonZeroLength);
+        for (int signum = -1; signum <= 1; signum++) {
+            BigInteger bi = new BigInteger(signum, magNonZeroLength, 0, 0);
+            Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0,
+                    "C: Zero length BigInteger != 0 for signum " + signum);
+        }
+
+        // --- tests for accurate creation of non-zero BigIntegers ---
+
+        for (int i = 0; i < SIZE; i++) {
+            // create reference value via a different code path from those tested
+            BigInteger reference = new BigInteger(2 + random.nextInt(336), 4, random);
+
+            byte[] refArray = reference.toByteArray();
+            int refLen = refArray.length;
+            int factor = random.nextInt(5);
+            int objLen = refArray.length + factor*random.nextInt(refArray.length) + 1;
+            int offset = random.nextInt(objLen - refLen);
+            byte[] objArray = new byte[objLen];
+            System.arraycopy(refArray, 0, objArray, offset, refLen);
+
+            BigInteger twosComp = new BigInteger(objArray, offset, refLen);
+            Assert.assertEquals(twosComp.compareTo(reference), 0,
+                    "Two's-complement BigInteger not equal for offset " +
+                        offset + " and length " + refLen);
+
+            boolean isNegative = random.nextBoolean();
+            BigInteger signMag = new BigInteger(isNegative ? -1 : 1, objArray, offset, refLen);
+            Assert.assertEquals(signMag.compareTo(isNegative ? reference.negate() : reference), 0,
+                    "Sign-magnitude BigInteger not equal for offset " +
+                        offset + " and length " + refLen);
+        }
+    }
+
+    private static void pow(int order) {
+        for (int i=0; i<SIZE; i++) {
+            // Test identity x^power == x*x*x ... *x
+            int power = random.nextInt(6) + 2;
+            BigInteger x = fetchNumber(order);
+            BigInteger y = x.pow(power);
+            BigInteger z = x;
+
+            for (int j=1; j<power; j++)
+                z = z.multiply(x);
+
+            Assert.assertEquals(y, z);
+        }
+    }
+
+    private static void square(int order) {
+        for (int i=0; i<SIZE; i++) {
+            // Test identity x^2 == x*x
+            BigInteger x  = fetchNumber(order);
+            BigInteger xx = x.multiply(x);
+            BigInteger x2 = x.pow(2);
+
+            Assert.assertEquals(x2, xx);
+        }
+    }
+
+    private static void checkResult(BigInteger expected, BigInteger actual, String failureMessage) {
+        Assert.assertEquals(expected.compareTo(actual), 0,
+                failureMessage + " - expected: " + expected + ", actual: " + actual);
+    }
+
+    private static void squareRootSmall() {
+        // A negative value should cause an exception.
+        BigInteger n = BigInteger.ONE.negate();
+        BigInteger s;
+        try {
+            s = n.sqrt();
+            // If sqrt() does not throw an exception that is a failure.
+            Assert.fail("sqrt() of negative number did not throw an exception");
+        } catch (ArithmeticException expected) {
+            // A negative value should cause an exception and is not a failure.
+        }
+
+        // A zero value should return BigInteger.ZERO.
+        checkResult(BigInteger.ZERO, BigInteger.ZERO.sqrt(), "sqrt(0) != BigInteger.ZERO");
+
+        // 1 <= value < 4 should return BigInteger.ONE.
+        long[] smalls = new long[] {1, 2, 3};
+        for (long small : smalls) {
+            checkResult(BigInteger.ONE, BigInteger.valueOf(small).sqrt(), "sqrt("+small+") != 1");
+        }
+    }
+
+    private static void squareRoot() {
+        squareRootSmall();
+
+
+        Function<BigInteger, Void> f = (n) -> {
+            // square root of n^2 -> n
+            BigInteger n2 = n.pow(2);
+            checkResult(n, n2.sqrt(), "sqrt() n^2 -> n");
+
+            // square root of n^2 + 1 -> n
+            BigInteger n2up = n2.add(BigInteger.ONE);
+            checkResult(n, n2up.sqrt(), "sqrt() n^2 + 1 -> n");
+
+            // square root of (n + 1)^2 - 1 -> n
+            BigInteger up = n.add(BigInteger.ONE).pow(2).subtract(BigInteger.ONE);
+            checkResult(n, up.sqrt(), "sqrt() (n + 1)^2 - 1 -> n");
+
+            // sqrt(n)^2 <= n
+            BigInteger s = n.sqrt();
+            Assert.assertFalse(s.multiply(s).compareTo(n) > 0,
+                    "sqrt(n)^2 > n for n = " + n);
+
+            // (sqrt(n) + 1)^2 > n
+            Assert.assertFalse(s.add(BigInteger.ONE).pow(2).compareTo(n) <= 0,
+                    "(sqrt(n) + 1)^2 <= n for n = " + n);
+            return null;
+        };
+
+        Stream.Builder<BigInteger> sb = Stream.builder();
+        int maxExponent = Double.MAX_EXPONENT + 1;
+        for (int i = 1; i <= maxExponent; i++) {
+            BigInteger p2 = BigInteger.ONE.shiftLeft(i);
+            sb.add(p2.subtract(BigInteger.ONE));
+            sb.add(p2);
+            sb.add(p2.add(BigInteger.ONE));
+        }
+        sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger());
+        sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger().add(BigInteger.ONE));
+        // "squareRoot for 2^N and 2^N - 1, 1 <= N <= Double.MAX_EXPONENT"
+        sb.build().map(f).collect(Collectors.toList());
+
+        IntStream ints = random.ints(SIZE, 4, Integer.MAX_VALUE);
+        ints.mapToObj(BigInteger::valueOf).map(f).collect(Collectors.toList());
+
+        LongStream longs = random.longs(SIZE, (long)Integer.MAX_VALUE + 1L,
+            Long.MAX_VALUE);
+        longs.mapToObj(BigInteger::valueOf).map(f).collect(Collectors.toList());
+
+        DoubleStream doubles = random.doubles(SIZE,
+            (double) Long.MAX_VALUE + 1.0, Math.sqrt(Double.MAX_VALUE));
+        doubles.mapToObj(x -> BigDecimal.valueOf(x).toBigInteger()).map(f).collect(Collectors.toList());
+    }
+
+    private static void squareRootAndRemainder() {
+        Function<BigInteger, Void> g = (n) -> {
+            BigInteger n2 = n.pow(2);
+
+            // square root of n^2 -> n
+            BigInteger[] actual = n2.sqrtAndRemainder();
+            checkResult(n, actual[0], "sqrtAndRemainder()[0]");
+            checkResult(BigInteger.ZERO, actual[1], "sqrtAndRemainder()[1]");
+
+            // square root of n^2 + 1 -> n
+            BigInteger n2up = n2.add(BigInteger.ONE);
+            actual = n2up.sqrtAndRemainder();
+            checkResult(n, actual[0], "sqrtAndRemainder()[0]");
+            checkResult(BigInteger.ONE, actual[1], "sqrtAndRemainder()[1]");
+
+            // square root of (n + 1)^2 - 1 -> n
+            BigInteger up = n.add(BigInteger.ONE).pow(2).subtract(BigInteger.ONE);
+            actual = up.sqrtAndRemainder();
+            checkResult(n, actual[0], "sqrtAndRemainder()[0]");
+            BigInteger r = up.subtract(n2);
+            checkResult(r, actual[1], "sqrtAndRemainder()[1]");
+            return null;
+        };
+
+        IntStream bits = random.ints(SIZE, 3, Short.MAX_VALUE);
+        bits.mapToObj(BigInteger::valueOf).map(g).collect(Collectors.toList());
+    }
+
+    private static void arithmetic(int order) {
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(order);
+            while(x.compareTo(BigInteger.ZERO) != 1)
+                x = fetchNumber(order);
+            BigInteger y = fetchNumber(order/2);
+            while(x.compareTo(y) == -1)
+                y = fetchNumber(order/2);
+            if (y.equals(BigInteger.ZERO))
+                y = y.add(BigInteger.ONE);
+
+            // Test identity ((x/y))*y + x%y - x == 0
+            // using separate divide() and remainder()
+            BigInteger baz = x.divide(y);
+            baz = baz.multiply(y);
+            baz = baz.add(x.remainder(y));
+            baz = baz.subtract(x);
+            Assert.assertEquals(baz, BigInteger.ZERO);
+        }
+
+        for (int i=0; i<100; i++) {
+            BigInteger x = fetchNumber(order);
+            while(x.compareTo(BigInteger.ZERO) != 1)
+                x = fetchNumber(order);
+            BigInteger y = fetchNumber(order/2);
+            while(x.compareTo(y) == -1)
+                y = fetchNumber(order/2);
+            if (y.equals(BigInteger.ZERO))
+                y = y.add(BigInteger.ONE);
+
+            // Test identity ((x/y))*y + x%y - x == 0
+            // using divideAndRemainder()
+            BigInteger baz[] = x.divideAndRemainder(y);
+            baz[0] = baz[0].multiply(y);
+            baz[0] = baz[0].add(baz[1]);
+            baz[0] = baz[0].subtract(x);
+            Assert.assertEquals(baz[0], BigInteger.ZERO);
+        }
+    }
+
+    /**
+     * Sanity test for Karatsuba and 3-way Toom-Cook multiplication.
+     * For each of the Karatsuba and 3-way Toom-Cook multiplication thresholds,
+     * construct two factors each with a mag array one element shorter than the
+     * threshold, and with the most significant bit set and the rest of the bits
+     * random. Each of these numbers will therefore be below the threshold but
+     * if shifted left be above the threshold. Call the numbers 'u' and 'v' and
+     * define random shifts 'a' and 'b' in the range [1,32]. Then we have the
+     * identity
+     * <pre>
+     * (u << a)*(v << b) = (u*v) << (a + b)
+     * </pre>
+     * For Karatsuba multiplication, the right hand expression will be evaluated
+     * using the standard naive algorithm, and the left hand expression using
+     * the Karatsuba algorithm. For 3-way Toom-Cook multiplication, the right
+     * hand expression will be evaluated using Karatsuba multiplication, and the
+     * left hand expression using 3-way Toom-Cook multiplication.
+     */
+    private static void multiplyLarge() {
+        BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA - 32 - 1);
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(BITS_KARATSUBA - 32 - 1);
+            BigInteger u = base.add(x);
+            int a = 1 + random.nextInt(31);
+            BigInteger w = u.shiftLeft(a);
+
+            BigInteger y = fetchNumber(BITS_KARATSUBA - 32 - 1);
+            BigInteger v = base.add(y);
+            int b = 1 + random.nextInt(32);
+            BigInteger z = v.shiftLeft(b);
+
+            BigInteger multiplyResult = u.multiply(v).shiftLeft(a + b);
+            BigInteger karatsubaMultiplyResult = w.multiply(z);
+
+            Assert.assertEquals(karatsubaMultiplyResult, multiplyResult);
+        }
+
+        base = base.shiftLeft(BITS_TOOM_COOK - BITS_KARATSUBA);
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(BITS_TOOM_COOK - 32 - 1);
+            BigInteger u = base.add(x);
+            BigInteger u2 = u.shiftLeft(1);
+            BigInteger y = fetchNumber(BITS_TOOM_COOK - 32 - 1);
+            BigInteger v = base.add(y);
+            BigInteger v2 = v.shiftLeft(1);
+
+            BigInteger multiplyResult = u.multiply(v).shiftLeft(2);
+            BigInteger toomCookMultiplyResult = u2.multiply(v2);
+
+            Assert.assertEquals(toomCookMultiplyResult, multiplyResult);
+        }
+    }
+
+    /**
+     * Sanity test for Karatsuba and 3-way Toom-Cook squaring.
+     * This test is analogous to {@link AbstractMethodError#multiplyLarge}
+     * with both factors being equal. The squaring methods will not be tested
+     * unless the <code>bigInteger.multiply(bigInteger)</code> tests whether
+     * the parameter is the same instance on which the method is being invoked
+     * and calls <code>square()</code> accordingly.
+     */
+    private static void squareLarge() {
+        BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA_SQUARE - 32 - 1);
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(BITS_KARATSUBA_SQUARE - 32 - 1);
+            BigInteger u = base.add(x);
+            int a = 1 + random.nextInt(31);
+            BigInteger w = u.shiftLeft(a);
+
+            BigInteger squareResult = u.multiply(u).shiftLeft(2*a);
+            BigInteger karatsubaSquareResult = w.multiply(w);
+
+            Assert.assertEquals(karatsubaSquareResult, squareResult);
+        }
+
+        base = base.shiftLeft(BITS_TOOM_COOK_SQUARE - BITS_KARATSUBA_SQUARE);
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(BITS_TOOM_COOK_SQUARE - 32 - 1);
+            BigInteger u = base.add(x);
+            int a = 1 + random.nextInt(31);
+            BigInteger w = u.shiftLeft(a);
+
+            BigInteger squareResult = u.multiply(u).shiftLeft(2*a);
+            BigInteger toomCookSquareResult = w.multiply(w);
+
+            Assert.assertEquals(toomCookSquareResult, squareResult);
+        }
+    }
+
+    /**
+     * Sanity test for Burnikel-Ziegler division.  The Burnikel-Ziegler division
+     * algorithm is used when each of the dividend and the divisor has at least
+     * a specified number of ints in its representation.  This test is based on
+     * the observation that if {@code w = u*pow(2,a)} and {@code z = v*pow(2,b)}
+     * where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if
+     * {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then
+     * {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}.  The test
+     * ensures that {@code v} is just under the B-Z threshold, that {@code z} is
+     * over the threshold and {@code w} is much larger than {@code z}. This
+     * implies that {@code u/v} uses the standard division algorithm and
+     * {@code w/z} uses the B-Z algorithm.  The results of the two algorithms
+     * are then compared using the observation described in the foregoing and
+     * if they are not equal a failure is logged.
+     */
+    private static void divideLarge() {
+        BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 33);
+        for (int i=0; i<SIZE; i++) {
+            BigInteger addend = new BigInteger(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 34, random);
+            BigInteger v = base.add(addend);
+
+            BigInteger u = v.multiply(BigInteger.valueOf(2 + random.nextInt(Short.MAX_VALUE - 1)));
+
+            if(random.nextBoolean()) {
+                u = u.negate();
+            }
+            if(random.nextBoolean()) {
+                v = v.negate();
+            }
+
+            int a = BITS_BURNIKEL_ZIEGLER_OFFSET + random.nextInt(16);
+            int b = 1 + random.nextInt(16);
+            BigInteger w = u.multiply(BigInteger.ONE.shiftLeft(a));
+            BigInteger z = v.multiply(BigInteger.ONE.shiftLeft(b));
+
+            BigInteger[] divideResult = u.divideAndRemainder(v);
+            divideResult[0] = divideResult[0].multiply(BigInteger.ONE.shiftLeft(a - b));
+            divideResult[1] = divideResult[1].multiply(BigInteger.ONE.shiftLeft(b));
+            BigInteger[] bzResult = w.divideAndRemainder(z);
+
+            Assert.assertEquals(divideResult[0].compareTo(bzResult[0]), 0);
+            Assert.assertEquals(divideResult[1].compareTo(bzResult[1]), 0);
+        }
+    }
+
+    private static void bitCount() {
+        for (int i=0; i<SIZE*10; i++) {
+            int x = random.nextInt();
+            BigInteger bigX = BigInteger.valueOf((long)x);
+            int bit = (x < 0 ? 0 : 1);
+            int tmp = x, bitCount = 0;
+            for (int j=0; j<32; j++) {
+                bitCount += ((tmp & 1) == bit ? 1 : 0);
+                tmp >>= 1;
+            }
+
+            Assert.assertEquals (bigX.bitCount(), bitCount);
+        }
+    }
+
+    private static void bitLength() {
+        for (int i=0; i<SIZE*10; i++) {
+            int x = random.nextInt();
+            BigInteger bigX = BigInteger.valueOf((long)x);
+            int signBit = (x < 0 ? 0x80000000 : 0);
+            int tmp = x, bitLength, j;
+            for (j=0; j<32 && (tmp & 0x80000000)==signBit; j++)
+                tmp <<= 1;
+            bitLength = 32 - j;
+
+            Assert.assertEquals(bigX.bitLength(), bitLength);
+        }
+    }
+
+    private static void bitOps(int order) {
+        for (int i=0; i<SIZE*5; i++) {
+            BigInteger x = fetchNumber(order);
+            BigInteger y;
+
+            // Test setBit and clearBit (and testBit)
+            if (x.signum() < 0) {
+                y = BigInteger.valueOf(-1);
+                for (int j=0; j<x.bitLength(); j++)
+                    if (!x.testBit(j))
+                        y = y.clearBit(j);
+            } else {
+                y = BigInteger.ZERO;
+                for (int j=0; j<x.bitLength(); j++)
+                    if (x.testBit(j))
+                        y = y.setBit(j);
+            }
+            Assert.assertEquals(y, x);
+
+            // Test flipBit (and testBit)
+            y = BigInteger.valueOf(x.signum()<0 ? -1 : 0);
+            for (int j=0; j<x.bitLength(); j++)
+                if (x.signum()<0  ^  x.testBit(j))
+                    y = y.flipBit(j);
+            Assert.assertEquals(y, x);
+        }
+
+        for (int i=0; i<SIZE*5; i++) {
+            BigInteger x = fetchNumber(order);
+
+            // Test getLowestSetBit()
+            int k = x.getLowestSetBit();
+            if (x.signum() == 0) {
+                Assert.assertEquals(k, -1);
+            } else {
+                BigInteger z = x.and(x.negate());
+                int j;
+                for (j=0; j<z.bitLength() && !z.testBit(j); j++)
+                    ;
+                Assert.assertEquals(k, j);
+            }
+        }
+    }
+
+    private static void bitwise(int order) {
+
+        // Test identity x^y == x|y &~ x&y
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(order);
+            BigInteger y = fetchNumber(order);
+            BigInteger z = x.xor(y);
+            BigInteger w = x.or(y).andNot(x.and(y));
+            Assert.assertEquals(z, w, "Test identity x^y == x|y &~ x&y");
+        }
+
+        // Test identity x &~ y == ~(~x | y)
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(order);
+            BigInteger y = fetchNumber(order);
+            BigInteger z = x.andNot(y);
+            BigInteger w = x.not().or(y).not();
+            Assert.assertEquals(z, w, "Test identity x &~ y == ~(~x | y)");
+        }
+    }
+
+    private static void shift(int order) {
+        for (int i=0; i<100; i++) {
+            BigInteger x = fetchNumber(order);
+            int n = Math.abs(random.nextInt()%200);
+
+            Assert.assertEquals(x.shiftLeft(n), x.multiply(BigInteger.valueOf(2L).pow(n)));
+
+            BigInteger y[] =x.divideAndRemainder(BigInteger.valueOf(2L).pow(n));
+            BigInteger z = (x.signum()<0 && y[1].signum()!=0
+                            ? y[0].subtract(BigInteger.ONE)
+                            : y[0]);
+
+            BigInteger b = x.shiftRight(n);
+
+            Assert.assertEquals(z, b);
+
+            Assert.assertEquals(x.shiftLeft(n).shiftRight(n), x);
+        }
+    }
+
+    private static void divideAndRemainder(int order) {
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(order).abs();
+            while(x.compareTo(BigInteger.valueOf(3L)) != 1)
+                x = fetchNumber(order).abs();
+            BigInteger z = x.divide(BigInteger.valueOf(2L));
+            BigInteger y[] = x.divideAndRemainder(x);
+
+            Assert.assertEquals(y[0], BigInteger.ONE);
+            Assert.assertEquals(y[1], BigInteger.ZERO);
+
+            y = x.divideAndRemainder(z);
+            Assert.assertEquals(y[0], BigInteger.valueOf(2));
+        }
+    }
+
+    private static void stringConv() {
+        // Generic string conversion.
+        for (int i=0; i<100; i++) {
+            byte[] xBytes = new byte[Math.abs(random.nextInt())%100+1];
+            random.nextBytes(xBytes);
+            BigInteger x = new BigInteger(xBytes);
+
+            for (int radix=Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) {
+                String result = x.toString(radix);
+                BigInteger test = new BigInteger(result, radix);
+                Assert.assertEquals(test, x,
+                        "BigInteger toString: "+x+" Test: "+test+" radix: " + radix);
+            }
+        }
+
+        // String conversion straddling the Schoenhage algorithm crossover
+        // threshold, and at twice and four times the threshold.
+        for (int k = 0; k <= 2; k++) {
+            int factor = 1 << k;
+            int upper = factor * BITS_SCHOENHAGE_BASE + 33;
+            int lower = upper - 35;
+
+            for (int bits = upper; bits >= lower; bits--) {
+                for (int i = 0; i < 50; i++) {
+                    BigInteger x = BigInteger.ONE.shiftLeft(bits - 1).or(new BigInteger(bits - 2, random));
+
+                    for (int radix = Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) {
+                        String result = x.toString(radix);
+                        BigInteger test = new BigInteger(result, radix);
+                        Assert.assertEquals(test, x,
+                                "BigInteger toString: "+x+" Test: "+test+" radix: " + radix);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void byteArrayConv(int order) {
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(order);
+            while (x.equals(BigInteger.ZERO))
+                x = fetchNumber(order);
+            BigInteger y = new BigInteger(x.toByteArray());
+            Assert.assertEquals(y, x, "orig is " + x + ", new is " + y);
+        }
+    }
+
+    private static void modInv(int order) {
+        for (int i=0; i<SIZE; i++) {
+            BigInteger x = fetchNumber(order);
+            while(x.equals(BigInteger.ZERO))
+                x = fetchNumber(order);
+            BigInteger m = fetchNumber(order).abs();
+            while(m.compareTo(BigInteger.ONE) != 1)
+                m = fetchNumber(order).abs();
+
+            try {
+                BigInteger inv = x.modInverse(m);
+                BigInteger prod = inv.multiply(x).remainder(m);
+
+                if (prod.signum() == -1)
+                    prod = prod.add(m);
+
+                Assert.assertEquals(prod, BigInteger.ONE);
+            } catch(ArithmeticException ignored) {
+            }
+        }
+    }
+
+    private static void modExp(int order1, int order2) {
+        for (int i=0; i<SIZE/10; i++) {
+            BigInteger m = fetchNumber(order1).abs();
+            while(m.compareTo(BigInteger.ONE) != 1)
+                m = fetchNumber(order1).abs();
+            BigInteger base = fetchNumber(order2);
+            BigInteger exp = fetchNumber(8).abs();
+
+            BigInteger z = base.modPow(exp, m);
+            BigInteger w = base.pow(exp.intValue()).mod(m);
+
+            Assert.assertEquals(z, w, "z is "+z+" w is "+w+" mod is "+m+" base is "+base+" exp is "+exp);
+        }
+    }
+
+    // This test is based on Fermat's theorem
+    // which is not ideal because base must not be multiple of modulus
+    // and modulus must be a prime or pseudoprime (Carmichael number)
+    private static void modExp2(int order) {
+        for (int i=0; i<10; i++) {
+            BigInteger m = new BigInteger(100, 5, random);
+            while(m.compareTo(BigInteger.ONE) != 1)
+                m = new BigInteger(100, 5, random);
+            BigInteger exp = m.subtract(BigInteger.ONE);
+            BigInteger base = fetchNumber(order).abs();
+            while(base.compareTo(m) != -1)
+                base = fetchNumber(order).abs();
+            while(base.equals(BigInteger.ZERO))
+                base = fetchNumber(order).abs();
+
+            BigInteger one = base.modPow(exp, m);
+            Assert.assertEquals(one, BigInteger.ONE, "m is "+m+" base is "+base+" exp is "+exp);
+        }
+    }
+
+    private static final int[] mersenne_powers = {
+        521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937,
+        21701, 23209, 44497, 86243, 110503, 132049, 216091, 756839, 859433,
+        1257787, 1398269, 2976221, 3021377, 6972593, 13466917 };
+
+    private static final long[] carmichaels = {
+      561,1105,1729,2465,2821,6601,8911,10585,15841,29341,41041,46657,52633,
+      62745,63973,75361,101101,115921,126217,162401,172081,188461,252601,
+      278545,294409,314821,334153,340561,399001,410041,449065,488881,512461,
+      225593397919L };
+
+    // Note: testing the larger ones takes too long.
+    private static final int NUM_MERSENNES_TO_TEST = 7;
+    // Note: this constant used for computed Carmichaels, not the array above
+    private static final int NUM_CARMICHAELS_TO_TEST = 5;
+
+    private static final String[] customer_primes = {
+        "120000000000000000000000000000000019",
+        "633825300114114700748351603131",
+        "1461501637330902918203684832716283019651637554291",
+        "779626057591079617852292862756047675913380626199",
+        "857591696176672809403750477631580323575362410491",
+        "910409242326391377348778281801166102059139832131",
+        "929857869954035706722619989283358182285540127919",
+        "961301750640481375785983980066592002055764391999",
+        "1267617700951005189537696547196156120148404630231",
+        "1326015641149969955786344600146607663033642528339" };
+
+    private static final BigInteger ZERO = BigInteger.ZERO;
+    private static final BigInteger ONE = BigInteger.ONE;
+    private static final BigInteger TWO = new BigInteger("2");
+    private static final BigInteger SIX = new BigInteger("6");
+    private static final BigInteger TWELVE = new BigInteger("12");
+    private static final BigInteger EIGHTEEN = new BigInteger("18");
+
+    private static void prime() {
+        BigInteger p1, p2, c1;
+
+        // Test consistency
+        for(int i=0; i<10; i++) {
+            p1 = BigInteger.probablePrime(100, random);
+            Assert.assertTrue(p1.isProbablePrime(100), p1.toString(16));
+        }
+
+        // Test some known Mersenne primes (2^n)-1
+        // The array holds the exponents, not the numbers being tested
+        for (int i=0; i<NUM_MERSENNES_TO_TEST; i++) {
+            p1 = new BigInteger("2");
+            p1 = p1.pow(mersenne_powers[i]);
+            p1 = p1.subtract(BigInteger.ONE);
+            Assert.assertTrue(p1.isProbablePrime(100), "Mersenne prime "+i+ " failed.");
+        }
+
+        // Test some primes reported by customers as failing in the past
+        for (int i=0; i<customer_primes.length; i++) {
+            p1 = new BigInteger(customer_primes[i]);
+            Assert.assertTrue(p1.isProbablePrime(100), "Customer prime "+i+ " failed.");
+        }
+
+        // Test some known Carmichael numbers.
+        for (int i=0; i<carmichaels.length; i++) {
+            c1 = BigInteger.valueOf(carmichaels[i]);
+            Assert.assertFalse(c1.isProbablePrime(100), "Carmichael "+i+ " reported as prime.");
+        }
+
+        // Test some computed Carmichael numbers.
+        // Numbers of the form (6k+1)(12k+1)(18k+1) are Carmichael numbers if
+        // each of the factors is prime
+        int found = 0;
+        BigInteger f1 = new BigInteger(40, 100, random);
+        while (found < NUM_CARMICHAELS_TO_TEST) {
+            BigInteger k = null;
+            BigInteger f2, f3;
+            f1 = f1.nextProbablePrime();
+            BigInteger[] result = f1.subtract(ONE).divideAndRemainder(SIX);
+            if (result[1].equals(ZERO)) {
+                k = result[0];
+                f2 = k.multiply(TWELVE).add(ONE);
+                if (f2.isProbablePrime(100)) {
+                    f3 = k.multiply(EIGHTEEN).add(ONE);
+                    if (f3.isProbablePrime(100)) {
+                        c1 = f1.multiply(f2).multiply(f3);
+                        Assert.assertFalse(c1.isProbablePrime(100), "Computed Carmichael "
+                                               +c1.toString(16));
+                        found++;
+                    }
+                }
+            }
+            f1 = f1.add(TWO);
+        }
+
+        // Test some composites that are products of 2 primes
+        for (int i=0; i<50; i++) {
+            p1 = BigInteger.probablePrime(100, random);
+            p2 = BigInteger.probablePrime(100, random);
+            c1 = p1.multiply(p2);
+            Assert.assertFalse(c1.isProbablePrime(100),
+                    "Composite failed "+c1.toString(16));
+        }
+
+        for (int i=0; i<4; i++) {
+            p1 = BigInteger.probablePrime(600, random);
+            p2 = BigInteger.probablePrime(600, random);
+            c1 = p1.multiply(p2);
+            Assert.assertFalse(c1.isProbablePrime(100),
+                    "Composite failed "+c1.toString(16));
+        }
+    }
+
+    private static final long[] primesTo100 = {
+        2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
+    };
+
+    private static final long[] aPrimeSequence = {
+        1999999003L, 1999999013L, 1999999049L, 1999999061L, 1999999081L,
+        1999999087L, 1999999093L, 1999999097L, 1999999117L, 1999999121L,
+        1999999151L, 1999999171L, 1999999207L, 1999999219L, 1999999271L,
+        1999999321L, 1999999373L, 1999999423L, 1999999439L, 1999999499L,
+        1999999553L, 1999999559L, 1999999571L, 1999999609L, 1999999613L,
+        1999999621L, 1999999643L, 1999999649L, 1999999657L, 1999999747L,
+        1999999763L, 1999999777L, 1999999811L, 1999999817L, 1999999829L,
+        1999999853L, 1999999861L, 1999999871L, 1999999873
+    };
+
+    private static void nextProbablePrime() throws Exception {
+        BigInteger p1, p2, p3;
+        p1 = p2 = p3 = ZERO;
+
+        // First test nextProbablePrime on the low range starting at zero
+        for (long l : primesTo100) {
+            p1 = p1.nextProbablePrime();
+            Assert.assertEquals(p1.longValue(), l,
+                    "low range primes failed: p1 is " + p1 + ", expected " + l);
+        }
+
+        // Test nextProbablePrime on a relatively small, known prime sequence
+        p1 = BigInteger.valueOf(aPrimeSequence[0]);
+        for (int i=1; i<aPrimeSequence.length; i++) {
+            p1 = p1.nextProbablePrime();
+            Assert.assertEquals(p1.longValue(), aPrimeSequence[i], "prime sequence failed");
+        }
+
+        // Next, pick some large primes, use nextProbablePrime to find the
+        // next one, and make sure there are no primes in between
+        for (int i=0; i<100; i+=10) {
+            p1 = BigInteger.probablePrime(50 + i, random);
+            p2 = p1.add(ONE);
+            p3 = p1.nextProbablePrime();
+            while(p2.compareTo(p3) < 0) {
+                Assert.assertFalse(p2.isProbablePrime(100),
+                        "nextProbablePrime failed along range "+p1.toString(16)+" to "+p3.toString(16));
+                p2 = p2.add(ONE);
+            }
+        }
+    }
+
+    // Android-changed: Replace File streams with ByteArray
+    public static void serialize() throws Exception {
+        String[] bitPatterns = {
+             "ffffffff00000000ffffffff00000000ffffffff00000000",
+             "ffffffffffffffffffffffff000000000000000000000000",
+             "ffffffff0000000000000000000000000000000000000000",
+             "10000000ffffffffffffffffffffffffffffffffffffffff",
+             "100000000000000000000000000000000000000000000000",
+             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "-ffffffff00000000ffffffff00000000ffffffff00000000",
+            "-ffffffffffffffffffffffff000000000000000000000000",
+            "-ffffffff0000000000000000000000000000000000000000",
+            "-10000000ffffffffffffffffffffffffffffffffffffffff",
+            "-100000000000000000000000000000000000000000000000",
+            "-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        };
+
+        for (String bitPattern : bitPatterns) {
+            BigInteger b1 = new BigInteger(bitPattern, 16);
+            BigInteger b2 = null;
+
+            try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
+                try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
+                    oos.writeObject(b1);
+                    oos.flush();
+                }
+
+                try (ByteArrayInputStream fis = new ByteArrayInputStream(fos.toByteArray());
+                        ObjectInputStream ois = new ObjectInputStream(fis)) {
+                    b2 = (BigInteger) ois.readObject();
+                }
+
+                Assert.assertEquals(b1, b2, "Serialized failed for hex " + b1.toString(16));
+                Assert.assertEquals(b1.or(b2), b1, "Serialized failed for hex " + b1.toString(16));
+            }
+        }
+
+        for(int i=0; i<10; i++) {
+            BigInteger b1 = fetchNumber(random.nextInt(100));
+            BigInteger b2 = null;
+
+            try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
+                try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
+                    oos.writeObject(b1);
+                    oos.flush();
+                }
+
+                try (ByteArrayInputStream fis = new ByteArrayInputStream(fos.toByteArray());
+                     ObjectInputStream ois = new ObjectInputStream(fis))
+                {
+                    b2 = (BigInteger)ois.readObject();
+                }
+            }
+
+            Assert.assertEquals(b1, b2, "Serialized failed for hex " + b1.toString(16));
+            Assert.assertEquals(b1.or(b2), b1, "Serialized failed for hex " + b1.toString(16));
+        }
+    }
+
+    private static final int ORDER_1 = ORDER_MEDIUM;
+    private static final int ORDER_2 = ORDER_SMALL;
+    private static final int ORDER_3 = ORDER_KARATSUBA;
+    private static final int ORDER_4 = ORDER_TOOM_COOK;
+
+    @Test
+    public void testConstructor() {
+        constructor();
+    }
+
+    @Test
+    public void testPrime() {
+        prime();
+    }
+
+    @Test
+    public void testNextProbablePrime() throws Exception {
+        nextProbablePrime();
+    }
+
+    @Test
+    public void testArithmetic() {
+        arithmetic(ORDER_1);   // small numbers
+        arithmetic(ORDER_3);   // Karatsuba range
+        arithmetic(ORDER_4);   // Toom-Cook / Burnikel-Ziegler range
+    }
+
+    @Test
+    public void testDivideAndReminder() {
+        divideAndRemainder(ORDER_1);   // small numbers
+        divideAndRemainder(ORDER_3);   // Karatsuba range
+        divideAndRemainder(ORDER_4);   // Toom-Cook / Burnikel-Ziegler range
+    }
+
+    @Test
+    public void testPow() {
+        pow(ORDER_1);
+        pow(ORDER_3);
+        pow(ORDER_4);
+    }
+
+    @Test
+    public void testSquare() {
+        square(ORDER_MEDIUM);
+        square(ORDER_KARATSUBA_SQUARE);
+        square(ORDER_TOOM_COOK_SQUARE);
+    }
+
+    @Test
+    public void testSquareRoot() {
+        squareRoot();
+    }
+
+    @Test
+    public void testSquareRootAndReminder() {
+        squareRootAndRemainder();
+    }
+
+    @Test
+    public void testBitCount() {
+        bitCount();
+    }
+
+    @Test
+    public void testBitLength() {
+        bitLength();
+    }
+
+    @Test
+    public void testBitOps() {
+        bitOps(ORDER_1);
+    }
+
+    @Test
+    public void testBitwise() {
+        bitwise(ORDER_1);
+    }
+
+    @Test
+    public void testShift() {
+        shift(ORDER_1);
+    }
+
+    @Test
+    public void testByteArrayConv() {
+        byteArrayConv(ORDER_1);
+    }
+
+    @Test
+    public void testModInv() {
+        modInv(ORDER_1);   // small numbers
+        modInv(ORDER_3);   // Karatsuba range
+        modInv(ORDER_4);   // Toom-Cook / Burnikel-Ziegler range
+    }
+
+    @Test
+    public void testModExp() {
+        modExp(ORDER_1, ORDER_2);
+        modExp2(ORDER_1);
+    }
+
+    @Test
+    public void testStringConv() {
+        stringConv();
+    }
+
+    @Test
+    public void testSerialize() throws Exception {
+        serialize();
+    }
+
+    @Test
+    public void testMultiplyLarge() {
+        multiplyLarge();
+    }
+
+    @Test
+    public void testSquareLarge() {
+        squareLarge();
+    }
+
+    @Test
+    public void testDivideLarge() {
+        divideLarge();
+    }
+
+    /*
+     * Get a random or boundary-case number. This is designed to provide
+     * a lot of numbers that will find failure points, such as max sized
+     * numbers, empty BigIntegers, etc.
+     *
+     * If order is less than 2, order is changed to 2.
+     */
+    private static BigInteger fetchNumber(int order) {
+        boolean negative = random.nextBoolean();
+        int numType = random.nextInt(7);
+        BigInteger result = null;
+        if (order < 2) order = 2;
+
+        switch (numType) {
+            case 0: // Empty
+                result = BigInteger.ZERO;
+                break;
+
+            case 1: // One
+                result = BigInteger.ONE;
+                break;
+
+            case 2: // All bits set in number
+                int numBytes = (order+7)/8;
+                byte[] fullBits = new byte[numBytes];
+                for(int i=0; i<numBytes; i++)
+                    fullBits[i] = (byte)0xff;
+                int excessBits = 8*numBytes - order;
+                fullBits[0] &= (1 << (8-excessBits)) - 1;
+                result = new BigInteger(1, fullBits);
+                break;
+
+            case 3: // One bit in number
+                result = BigInteger.ONE.shiftLeft(random.nextInt(order));
+                break;
+
+            case 4: // Random bit density
+                byte[] val = new byte[(order+7)/8];
+                int iterations = random.nextInt(order);
+                for (int i=0; i<iterations; i++) {
+                    int bitIdx = random.nextInt(order);
+                    val[bitIdx/8] |= 1 << (bitIdx%8);
+                }
+                result = new BigInteger(1, val);
+                break;
+            case 5: // Runs of consecutive ones and zeros
+                result = ZERO;
+                int remaining = order;
+                int bit = random.nextInt(2);
+                while (remaining > 0) {
+                    int runLength = Math.min(remaining, random.nextInt(order));
+                    result = result.shiftLeft(runLength);
+                    if (bit > 0)
+                        result = result.add(ONE.shiftLeft(runLength).subtract(ONE));
+                    remaining -= runLength;
+                    bit = 1 - bit;
+                }
+                break;
+
+            default: // random bits
+                result = new BigInteger(order, random);
+        }
+
+        if (negative)
+            result = result.negate();
+
+        return result;
+    }
+
+}
diff --git a/ojluni/src/test/java/math/BigInteger/CompareToTests.java b/ojluni/src/test/java/math/BigInteger/CompareToTests.java
new file mode 100644
index 0000000..abb8b4c
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/CompareToTests.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2006, 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.
+ *
+ * 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 test.java.math.BigInteger;
+
+/*
+ * @test
+ * @bug 6473768
+ * @summary Tests of BigInteger.compareTo
+ * @author Joseph D. Darcy
+ */
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import static java.math.BigInteger.*;
+
+// Android-changed: Replace error printing with asserts.
+public class CompareToTests {
+
+    @Test
+    public void compareToTests() {
+        final BigInteger MINUS_ONE = BigInteger.ONE.negate();
+        final BigInteger TWO_POW_126 = ONE.shiftLeft(126);
+        final BigInteger TWO_POW_127 = ONE.shiftLeft(127);
+        final BigInteger TWO_POW_128 = ONE.shiftLeft(128);
+
+        // First operand, second operand, expected compareTo result
+        BigInteger [][] testCases = {
+            // Basics
+            {valueOf(0),        valueOf(0),     ZERO},
+            {valueOf(0),        valueOf(1),     MINUS_ONE},
+            {valueOf(1),        valueOf(2),     MINUS_ONE},
+            {valueOf(2),        valueOf(1),     ONE},
+            {valueOf(10),       valueOf(10),    ZERO},
+
+            // Various relative lengths of internal mag array.
+            {TWO_POW_127,                 TWO_POW_127,                 ZERO},
+            {TWO_POW_127.negate(),        TWO_POW_127,                 MINUS_ONE},
+
+            {TWO_POW_128.or(TWO_POW_126), TWO_POW_128,                 ONE},
+            {TWO_POW_128.or(TWO_POW_126), TWO_POW_128.negate(),        ONE},
+
+            {TWO_POW_128,                 TWO_POW_128.or(TWO_POW_126), MINUS_ONE},
+            {TWO_POW_128.negate(),        TWO_POW_128.or(TWO_POW_126), MINUS_ONE},
+
+            {TWO_POW_127,                 TWO_POW_128,                 MINUS_ONE},
+            {TWO_POW_127.negate(),        TWO_POW_128,                 MINUS_ONE},
+
+            {TWO_POW_128,                 TWO_POW_127,                 ONE},
+            {TWO_POW_128.negate(),        TWO_POW_127,                 MINUS_ONE},
+
+            // Long boundary and near boundary values
+            {valueOf(Long.MAX_VALUE),            valueOf(Long.MAX_VALUE), ZERO},
+            {valueOf(Long.MAX_VALUE).negate(),   valueOf(Long.MAX_VALUE), MINUS_ONE},
+
+            {valueOf(Long.MAX_VALUE-1),          valueOf(Long.MAX_VALUE), MINUS_ONE},
+            {valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MAX_VALUE), MINUS_ONE},
+
+            {valueOf(Long.MIN_VALUE),            valueOf(Long.MAX_VALUE), MINUS_ONE},
+            {valueOf(Long.MIN_VALUE).negate(),   valueOf(Long.MAX_VALUE), ONE},
+
+            {valueOf(Long.MIN_VALUE+1),          valueOf(Long.MAX_VALUE), MINUS_ONE},
+            {valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MAX_VALUE), ZERO},
+
+            {valueOf(Long.MAX_VALUE),            valueOf(Long.MIN_VALUE), ONE},
+            {valueOf(Long.MAX_VALUE).negate(),   valueOf(Long.MIN_VALUE), ONE},
+
+            {valueOf(Long.MAX_VALUE-1),          valueOf(Long.MIN_VALUE), ONE},
+            {valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MIN_VALUE), ONE},
+
+            {valueOf(Long.MIN_VALUE),            valueOf(Long.MIN_VALUE), ZERO},
+            {valueOf(Long.MIN_VALUE).negate(),   valueOf(Long.MIN_VALUE), ONE},
+
+            {valueOf(Long.MIN_VALUE+1),          valueOf(Long.MIN_VALUE), ONE},
+            {valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MIN_VALUE), ONE},
+        };
+
+        for (BigInteger[] testCase : testCases) {
+            BigInteger a = testCase[0];
+            BigInteger a_negate = a.negate();
+            BigInteger b = testCase[1];
+            BigInteger b_negate = b.negate();
+            int expected = testCase[2].intValue();
+
+            compareToTest(a,        b,         expected);
+            compareToTest(a_negate, b_negate, -expected);
+        }
+    }
+
+    private static void compareToTest(BigInteger a, BigInteger b, int expected) {
+        int result = a.compareTo(b);
+        int failed = (result==expected) ? 0 : 1;
+        if (failed == 1) {
+            Assert.fail("(" + a + ").compareTo(" + b + ") => " + result +
+                               "\n\tExpected " + expected);
+        }
+    }
+
+}
diff --git a/ojluni/src/test/java/math/BigInteger/ModPow.java b/ojluni/src/test/java/math/BigInteger/ModPow.java
new file mode 100644
index 0000000..b31c0f6
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/ModPow.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1998, 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @bug 4181191
+ * @summary test BigInteger modPow method
+ */
+package test.java.math.BigInteger;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class ModPow {
+
+    @Test
+    public void testModPow() {
+        Random rnd = new Random(1234);
+
+        for (int i=0; i<2000; i++) {
+            BigInteger m = new BigInteger(800, rnd);
+            BigInteger base = new BigInteger(16, rnd);
+            if (rnd.nextInt() % 2 == 0)
+                base = base.negate();
+            BigInteger exp = new BigInteger(8, rnd);
+
+            BigInteger z = base.modPow(exp, m);
+            BigInteger w = base.pow(exp.intValue()).mod(m);
+            Assert.assertEquals(z, w,
+                    base +" ** " + exp + " mod "+ m + " modPow : " + z + "pow.mod: " + w);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/OperatorNpeTests.java b/ojluni/src/test/java/math/BigInteger/OperatorNpeTests.java
new file mode 100644
index 0000000..5940249
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/OperatorNpeTests.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6365176
+ * @summary Get NullPointerExceptions when expected
+ * @author Joseph D. Darcy
+ */
+package test.java.math.BigInteger;
+
+import java.math.*;
+import static java.math.BigInteger.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class OperatorNpeTests {
+
+    @Test
+    public void testOperatorsNpe() throws NullPointerException {
+        BigInteger[] specialValues = {ZERO, ONE, TEN};
+
+        for (BigInteger bd : specialValues) {
+            BigInteger result;
+            try {
+                result = bd.multiply(null);
+                Assert.fail("Instead of NPE got " + result);
+            } catch (NullPointerException npe) {
+                ; // Expected
+            }
+
+            try {
+                result = bd.divide(null);
+                Assert.fail("Instead of NPE got " + result);
+            } catch (NullPointerException npe) {
+                ; // Expected
+            }
+
+            try {
+                result = bd.add(null);
+                Assert.fail("Instead of NPE got " + result);
+            } catch (NullPointerException npe) {
+                ; // Expected
+            }
+
+            try {
+                result = bd.subtract(null);
+                Assert.fail("Instead of NPE got " + result);
+            } catch (NullPointerException npe) {
+                ; // Expected
+            }
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/PrimeTest.java b/ojluni/src/test/java/math/BigInteger/PrimeTest.java
new file mode 100644
index 0000000..e0e4c88
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/PrimeTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+/*
+ * @test
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main PrimeTest
+ * @bug 8026236 8074460 8078672
+ * @summary test primality verification methods in BigInteger (use -Dseed=X to set PRNG seed)
+ * @author bpb
+ * @key randomness
+ */
+package test.java.math.BigInteger;
+
+import java.math.BigInteger;
+import java.util.BitSet;
+import java.util.List;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.SplittableRandom;
+import java.util.TreeSet;
+import static java.util.stream.Collectors.toCollection;
+import static java.util.stream.Collectors.toList;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class PrimeTest {
+
+    private static final int DEFAULT_UPPER_BOUND = 1299709; // 100000th prime
+    private static final int DEFAULT_CERTAINTY = 100;
+    private static final int NUM_NON_PRIMES = 10000;
+
+    @Test
+    public void testPrimes() throws Exception {
+        // Get primes through specified bound (inclusive) and Integer.MAX_VALUE
+        NavigableSet<BigInteger> primes = getPrimes();
+
+        // Check whether known primes are identified as such
+        checkPrime(primes, DEFAULT_CERTAINTY);
+
+        // Check whether known non-primes are not identified as primes
+        checkNonPrime(primes, DEFAULT_CERTAINTY);
+
+        checkMersennePrimes(DEFAULT_CERTAINTY);
+    }
+
+    /**
+     * Create a {@code BitSet} wherein a set bit indicates the corresponding
+     * index plus 2 is prime. That is, if bit N is set, then the integer N + 2
+     * is prime. The values 0 and 1 are intentionally excluded. See the
+     * <a
+     * href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Algorithm_description">
+     * Sieve of Eratosthenes</a> algorithm description for more information.
+     *
+     * @return bits indicating which indexes represent primes
+     */
+    private static BitSet createPrimes() {
+        int nbits = PrimeTest.DEFAULT_UPPER_BOUND - 1;
+        BitSet bs = new BitSet(nbits);
+        for (int p = 2; p * p < PrimeTest.DEFAULT_UPPER_BOUND;) {
+            for (int i = p * p; i < nbits + 2; i += p) {
+                bs.set(i - 2, true);
+            }
+            do {
+                ++p;
+            } while (p > 1 && bs.get(p - 2));
+        }
+        bs.flip(0, nbits);
+        return bs;
+    }
+
+    /**
+     * Load the primes up to the specified bound (inclusive) into a
+     * {@code NavigableSet}, appending the prime {@code Integer.MAX_VALUE}.
+     *
+     * @return a set of primes
+     */
+    private static NavigableSet<BigInteger> getPrimes() {
+        BitSet bs = createPrimes();
+        NavigableSet<BigInteger> primes = bs.stream()
+                .mapToObj(p -> BigInteger.valueOf(p + 2))
+                .collect(toCollection(TreeSet::new));
+        primes.add(BigInteger.valueOf(Integer.MAX_VALUE));
+        return primes;
+    }
+
+    /**
+     * Verifies whether the fraction of probable primes detected is at least 1 -
+     * 1/2^certainty.
+     */
+    private static void checkPrime(Set<BigInteger> primes, int certainty) {
+        long probablePrimes = (primes.parallelStream())
+                .filter(bi -> bi.isProbablePrime(certainty))
+                .count();
+
+        // N = certainty / 2
+        // Success if p/t >= 1 - 1/4^N
+        // or (p/t)*4^N >= 4^N - 1
+        // or p*4^N >= t*(4^N - 1)
+        BigInteger p = BigInteger.valueOf(probablePrimes);
+        BigInteger t = BigInteger.valueOf(primes.size());
+        BigInteger fourToTheC = BigInteger.valueOf(4).pow(certainty / 2);
+        BigInteger fourToTheCMinusOne = fourToTheC.subtract(BigInteger.ONE);
+        BigInteger left = p.multiply(fourToTheC);
+        BigInteger right = t.multiply(fourToTheCMinusOne);
+
+        Assert.assertFalse(left.compareTo(right) < 0,
+                "Probable prime certainty test failed");
+    }
+
+    /**
+     * Verifies whether all {@code BigInteger}s in the tested range for which
+     * {@code isProbablePrime()} returns {@code false} are <i>not</i>
+     * prime numbers.
+     */
+    private static void checkNonPrime(NavigableSet<BigInteger> primes, int certainty) {
+        int maxPrime = DEFAULT_UPPER_BOUND;
+        try {
+            maxPrime = primes.last().intValueExact();
+        } catch (ArithmeticException e) {
+            // ignore it
+        }
+
+        // Create a list of non-prime BigIntegers.
+        SplittableRandom splitRandom = new SplittableRandom(0L);
+        List<BigInteger> nonPrimeBigInts = (splitRandom)
+                .ints(NUM_NON_PRIMES, 2, maxPrime).mapToObj(BigInteger::valueOf)
+                .filter(b -> !b.isProbablePrime(certainty)).collect(toList());
+
+        // If there are any non-probable primes also in the primes list then fail.
+        boolean failed = nonPrimeBigInts.stream().anyMatch(primes::contains);
+
+        // In the event, print which purported non-primes were actually prime.
+        if (failed) {
+            for (BigInteger bigInt : nonPrimeBigInts) {
+                if (primes.contains(bigInt)) {
+                    Assert.fail("Prime value thought to be non-prime: " + bigInt);
+                }
+            }
+        }
+    }
+
+    /**
+     * Verifies whether a specified subset of Mersenne primes are correctly
+     * identified as being prime. See
+     * <a href="https://en.wikipedia.org/wiki/Mersenne_prime">Mersenne prime</a>
+     * for more information.
+     */
+    private static void checkMersennePrimes(int certainty) {
+        int[] MERSENNE_EXPONENTS = {
+            2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
+            2281, 3217, 4253, // uncomment remaining array elements to make this test run a long time
+            /* 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497,
+            86243, 110503, 132049, 216091, 756839, 859433, 1257787, 1398269,
+            2976221, 3021377, 6972593, 13466917, 20996011, 24036583, 25964951,
+            30402457, 32582657, 37156667, 42643801, 43112609, 57885161 */
+        };
+
+        for (int n : MERSENNE_EXPONENTS) {
+            BigInteger mp = BigInteger.ONE.shiftLeft(n).subtract(BigInteger.ONE);
+            Assert.assertTrue(mp.isProbablePrime(certainty),
+                    "Mp with p = "+n+" not classified as prime");
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/PrimitiveConversionTests.java b/ojluni/src/test/java/math/BigInteger/PrimitiveConversionTests.java
new file mode 100644
index 0000000..834f864
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/PrimitiveConversionTests.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1998, 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.
+ *
+ * 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 test.java.math.BigInteger;
+
+import static java.math.BigInteger.ONE;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 7131192
+ * @summary This test ensures that BigInteger.floatValue() and
+ *          BigInteger.doubleValue() behave correctly.
+ * @author Louis Wasserman
+ */
+
+// Android-changed: Replace error printing with asserts.
+public class PrimitiveConversionTests {
+    static final List<BigInteger> ALL_BIGINTEGER_CANDIDATES;
+
+    static {
+        List<BigInteger> samples = new ArrayList<>();
+        // Now add values near 2^N for lots of values of N.
+        for (int exponent : Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 31, 32, 33,
+                34, 62, 63, 64, 65, 71, 72, 73, 79, 80, 81, 255, 256, 257, 511,
+                512, 513, Double.MAX_EXPONENT - 1, Double.MAX_EXPONENT,
+                Double.MAX_EXPONENT + 1, 2000, 2001, 2002)) {
+            BigInteger x = ONE.shiftLeft(exponent);
+            for (BigInteger y : Arrays.asList(x, x.add(ONE), x.subtract(ONE))) {
+                samples.add(y);
+                samples.add(y.negate());
+            }
+        }
+
+        Random rng = new Random(1234567);
+        for (int i = 0; i < 2000; i++) {
+            samples.add(new BigInteger(rng.nextInt(2000), rng));
+        }
+
+        ALL_BIGINTEGER_CANDIDATES = Collections.unmodifiableList(samples);
+    }
+
+    @Test
+    public void testDoubleValue() {
+        for (BigInteger big : ALL_BIGINTEGER_CANDIDATES) {
+            double expected = Double.parseDouble(big.toString());
+            double actual = big.doubleValue();
+
+            // should be bitwise identical
+            Assert.assertEquals(Double.doubleToRawLongBits(actual),
+                    Double.doubleToRawLongBits(expected));
+        }
+    }
+
+    @Test
+    public void testFloatValue() {
+        for (BigInteger big : ALL_BIGINTEGER_CANDIDATES) {
+            float expected = Float.parseFloat(big.toString());
+            float actual = big.floatValue();
+
+            // should be bitwise identical
+            Assert.assertEquals(Float.floatToRawIntBits(actual),
+                    Float.floatToRawIntBits(expected));
+        }
+    }
+
+}
diff --git a/ojluni/src/test/java/math/BigInteger/ProbablePrime.java b/ojluni/src/test/java/math/BigInteger/ProbablePrime.java
new file mode 100644
index 0000000..158c0e8
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/ProbablePrime.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4654323
+ * @summary Tests functionality of isProbablePrime(Integer.MAX_VALUE)
+ */
+package test.java.math.BigInteger;
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class ProbablePrime {
+
+    @Test
+    public void testProbablePrime() {
+        BigInteger num = new BigInteger("4");
+        int[] certainties = {-1, 0, 1, 2, 100, Integer.MAX_VALUE - 1, Integer.MAX_VALUE};
+        boolean[] expectations = {true, true, false, false, false, false, false};
+
+        for (int i = 0; i < certainties.length; i++) {
+            boolean b = num.isProbablePrime(certainties[i]);
+            Assert.assertEquals(b, expectations[i], "Unexpected answer " + b +
+                        " for certainty " +  certainties[i]);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/StringConstructor.java b/ojluni/src/test/java/math/BigInteger/StringConstructor.java
new file mode 100644
index 0000000..b7be11b
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/StringConstructor.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2001, 2007, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4489146 5017980
+ * @summary tests String constructors of BigInteger
+ * @author Joseph D. Darcy
+ */
+package test.java.math.BigInteger;
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class StringConstructor {
+
+    @Test
+    public void testStringConstructor() {
+        // Good strings
+        constructWithoutError("0", 0L);
+        constructWithoutError("000000000000000000", 0L);
+        constructWithoutError("1", 1L);
+        constructWithoutError("-1", -1L);
+        constructWithoutError("+1", +1L);
+        constructWithoutError( "123456789123456789", 123456789123456789L);
+        constructWithoutError("+123456789123456789", 123456789123456789L);
+        constructWithoutError("-123456789123456789", -123456789123456789L);
+        constructWithoutError(Integer.toString(Integer.MIN_VALUE),
+                              (long)Integer.MIN_VALUE);
+        constructWithoutError(Integer.toString(Integer.MAX_VALUE),
+                              (long)Integer.MAX_VALUE);
+        constructWithoutError(Long.toString(Long.MIN_VALUE),
+                              Long.MIN_VALUE);
+        constructWithoutError(Long.toString(Long.MAX_VALUE),
+                              Long.MAX_VALUE);
+
+        // Bad strings
+        constructWithError("");
+        constructWithError("-");
+        constructWithError("+");
+        constructWithError("--");
+        constructWithError("++");
+        constructWithError("-000-0");
+        constructWithError("+000+0");
+        constructWithError("+000-0");
+        constructWithError("--1234567890");
+        constructWithError("++1234567890");
+        constructWithError("-0-12345678");
+        constructWithError("+0+12345678");
+        constructWithError("--12345678-12345678-12345678");
+        constructWithError("++12345678+12345678+12345678");
+        constructWithError("12345-");
+        constructWithError("12345+");
+    }
+
+    // this method adapted from ../BigDecimal/StringConstructor.java
+    private static void constructWithError(String badString) {
+        try {
+            BigInteger bi = new BigInteger(badString);
+            Assert.fail(badString + " accepted");
+        } catch(NumberFormatException e) {
+            // expected
+        }
+    }
+
+    private static void constructWithoutError(String goodString, long value) {
+        BigInteger bi = new BigInteger(goodString);
+        Assert.assertEquals(bi.longValue(), value,
+                String.format("From ``%s'' expected %d, got %s.\n", goodString, value, bi));
+    }
+
+}
diff --git a/ojluni/src/test/java/math/BigInteger/TestValueExact.java b/ojluni/src/test/java/math/BigInteger/TestValueExact.java
new file mode 100644
index 0000000..92e49783
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/TestValueExact.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6371401
+ * @summary Tests of fooValueExact methods
+ * @author Joseph D. Darcy
+ */
+package test.java.math.BigInteger;
+
+import java.math.BigInteger;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class TestValueExact {
+
+    @Test
+    public void testLongValueExact() {
+        BigInteger[] inRange = {
+            BigInteger.valueOf(Long.MIN_VALUE),
+            BigInteger.ZERO,
+            BigInteger.valueOf(Long.MAX_VALUE)
+        };
+
+        BigInteger[] outOfRange = {
+            BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE),
+            BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE)
+        };
+
+        for (BigInteger bi : inRange) {
+            Assert.assertEquals(bi.longValueExact(), bi.longValue(),
+                    "Mismatching int conversion for " + bi);
+        }
+
+        for (BigInteger bi : outOfRange) {
+            try {
+                long value = bi.longValueExact();
+                Assert.fail("Failed to get expected exception on " + bi + " got " + value);
+            } catch(ArithmeticException ae) {
+                ; // Expected
+            }
+        }
+    }
+
+    @Test
+    public void testIntValueExact() {
+        BigInteger[] inRange = {
+            BigInteger.valueOf(Integer.MIN_VALUE),
+            BigInteger.ZERO,
+            BigInteger.ONE,
+            BigInteger.TEN,
+            BigInteger.valueOf(Integer.MAX_VALUE)
+        };
+
+        BigInteger[] outOfRange = {
+            BigInteger.valueOf((long)Integer.MIN_VALUE - 1),
+            BigInteger.valueOf((long)Integer.MAX_VALUE + 1)
+        };
+
+        for (BigInteger bi : inRange) {
+            Assert.assertEquals(bi.intValueExact(), bi.intValue(),
+                    "Mismatching int conversion for " + bi);
+        }
+
+        for (BigInteger bi : outOfRange) {
+            try {
+                int value = bi.intValueExact();
+                Assert.fail("Failed to get expected exception on " + bi + " got " + value);
+            } catch(ArithmeticException ae) {
+                ; // Expected
+            }
+        }
+    }
+
+    @Test
+    public void testShortValueExact() {
+        BigInteger[] inRange = {
+            BigInteger.valueOf(Short.MIN_VALUE),
+            BigInteger.ZERO,
+            BigInteger.ONE,
+            BigInteger.TEN,
+            BigInteger.valueOf(Short.MAX_VALUE)
+        };
+
+        BigInteger[] outOfRange = {
+            BigInteger.valueOf((long)Integer.MIN_VALUE - 1),
+            BigInteger.valueOf((long)Integer.MIN_VALUE),
+            BigInteger.valueOf(   (int)Short.MIN_VALUE - 1),
+            BigInteger.valueOf(   (int)Short.MAX_VALUE + 1),
+            BigInteger.valueOf((long)Integer.MAX_VALUE),
+            BigInteger.valueOf((long)Integer.MAX_VALUE + 1)
+        };
+
+        for (BigInteger bi : inRange) {
+            Assert.assertEquals(bi.shortValueExact(), bi.intValue(),
+                    "Mismatching int conversion for " + bi);
+        }
+
+        for (BigInteger bi : outOfRange) {
+            try {
+                int value = bi.shortValueExact();
+                Assert.fail("Failed to get expected exception on " + bi + " got " + value);
+            } catch(ArithmeticException ae) {
+                ; // Expected
+            }
+        }
+    }
+
+    @Test
+    public void testByteValueExact() {
+        BigInteger[] inRange = {
+            BigInteger.valueOf(Byte.MIN_VALUE),
+            BigInteger.valueOf(0),
+            BigInteger.ONE,
+            BigInteger.TEN,
+            BigInteger.valueOf(Byte.MAX_VALUE)
+        };
+
+        BigInteger[] outOfRange = {
+            BigInteger.valueOf((long)Integer.MIN_VALUE - 1),
+            BigInteger.valueOf((long)Integer.MIN_VALUE),
+            BigInteger.valueOf(   (int)Short.MIN_VALUE - 1),
+            BigInteger.valueOf(   (int)Short.MIN_VALUE),
+            BigInteger.valueOf(    (int)Byte.MIN_VALUE - 1),
+            BigInteger.valueOf(    (int)Byte.MAX_VALUE + 1),
+            BigInteger.valueOf(   (int)Short.MAX_VALUE + 1),
+            BigInteger.valueOf(   (int)Short.MAX_VALUE),
+            BigInteger.valueOf((long)Integer.MAX_VALUE),
+            BigInteger.valueOf((long)Integer.MAX_VALUE + 1)
+        };
+
+        for (BigInteger bi : inRange) {
+            Assert.assertEquals(bi.byteValueExact(), bi.intValue(),
+                    "Mismatching int conversion for " + bi);
+        }
+
+        for (BigInteger bi : outOfRange) {
+            try {
+                int value = bi.byteValueExact();
+                Assert.fail("Failed to get expected exception on " + bi + " got " + value);
+            } catch(ArithmeticException ae) {
+                ; // Expected
+            }
+        }
+    }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/UnicodeConstructor.java b/ojluni/src/test/java/math/BigInteger/UnicodeConstructor.java
new file mode 100644
index 0000000..b6b18e8
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/UnicodeConstructor.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1998, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4040456
+ * @summary Test biginteger constructor with i18n string
+ */
+package test.java.math.BigInteger;
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * This class tests to see if creating a biginteger with an unicode japanese zero and one succeeds
+ */
+
+// Android-changed: Replace error printing with asserts.
+public class UnicodeConstructor {
+
+    @Test
+    public void testUnicodeConstructor() {
+
+        try {
+            // the code for japanese zero
+            BigInteger b1 = new BigInteger("\uff10");
+
+            // Japanese 1010
+            BigInteger b2 = new BigInteger("\uff11\uff10\uff11\uff10");
+
+            // Android-added: more valid inputs
+            final Object[][] inputs = {
+                { "\u0030", 0 },                      // ASCII "0"
+                { "\u0031\u0030\u0031\u0030", 1010 }, // ASCII "1010"
+                { "\u0660", 0 },                      // Arabic-Indic Digit Zero
+                { "\u0661\u0660\u0661\u0660", 1010 }, // Arabic-Indic Digit, "1010"
+                { "\u09e6", 0 },                      // Bengali Digit Zero
+                { "\u09e7\u09e6\u09e7\u09e6", 1010 }, // Bengali Digit, "1010"
+            };
+            for (Object[] test : inputs) {
+                BigInteger b = new BigInteger((String)test[0]);
+                Assert.assertEquals(b.intValue(), (int)test[1]);
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            Assert.fail("BigInteger is not accepting unicode initializers.");
+        }
+
+    }
+
+}
diff --git a/ojluni/src/test/java/security/cert/URICertStoreParameters/TestBasic.java b/ojluni/src/test/java/security/cert/URICertStoreParameters/TestBasic.java
new file mode 100644
index 0000000..baa44d5
--- /dev/null
+++ b/ojluni/src/test/java/security/cert/URICertStoreParameters/TestBasic.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.security.cert.URICertStoreParameters;
+
+
+import java.security.cert.CertStore;
+import java.security.cert.URICertStoreParameters;
+import java.net.URI;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+
+/*
+ * @test
+ * @bug 8038084
+ * @summary Basic testing for URICertStoreParameters
+ * @run main TestBasic
+ */
+public class TestBasic {
+
+    @Test
+    public static void testURICertStoreParameters(String[] args) throws Exception {
+        String str1 = "ldap://myownhost:5000/";
+        String str2 = "ldap://myownhost:5000/cn=foo";
+        test(str1, str2);
+        System.out.println("Test passed");
+    }
+
+    private static void test(String str1, String str2) throws Exception {
+        URICertStoreParameters p1 = new URICertStoreParameters(new URI(str1));
+        URICertStoreParameters p1Too = p1.clone();
+        assertEquals(p1Too, p1);
+        assertEquals(p1Too.getURI(), p1.getURI());
+
+        p1Too = new URICertStoreParameters(new URI(str1));
+        URICertStoreParameters p2 = new URICertStoreParameters(new URI(str2));
+
+        assertNotNull(p1);
+        assertEquals(p1, p1);
+        assertEquals(p1.hashCode(), p1.hashCode());
+        assertEquals(p1Too, p1);
+        assertEquals(p1, p1Too);
+        assertEquals(p1Too.hashCode(), p1.hashCode());
+        assertEquals(p1, p2);
+        assertEquals(p1Too, p2);
+    }
+}
diff --git a/ojluni/src/test/java/util/Arrays/ArraysEqCmpTest.java b/ojluni/src/test/java/util/Arrays/ArraysEqCmpTest.java
new file mode 100644
index 0000000..727f7dc
--- /dev/null
+++ b/ojluni/src/test/java/util/Arrays/ArraysEqCmpTest.java
@@ -0,0 +1,1117 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.util.Arrays;
+
+/*
+ * @test
+ * @bug 8033148 8141409
+ * @summary tests for array equals and compare
+ * @run testng ArraysEqCmpTest
+ */
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BiFunction;
+import java.util.function.LongFunction;
+import java.util.stream.IntStream;
+
+public class ArraysEqCmpTest {
+
+    // Maximum width in bits
+    static final int MAX_WIDTH = 512;
+
+    static final Map<Class, Integer> typeToWidth;
+
+    static {
+        typeToWidth = new HashMap<>();
+        typeToWidth.put(boolean.class, Byte.SIZE);
+        typeToWidth.put(byte.class, Byte.SIZE);
+        typeToWidth.put(short.class, Short.SIZE);
+        typeToWidth.put(char.class, Character.SIZE);
+        typeToWidth.put(int.class, Integer.SIZE);
+        typeToWidth.put(long.class, Long.SIZE);
+        typeToWidth.put(float.class, Float.SIZE);
+        typeToWidth.put(double.class, Double.SIZE);
+        typeToWidth.put(Object.class, Integer.SIZE); // @@@ 32 or 64?
+    }
+
+    static int arraySizeFor(Class<?> type) {
+        type = type.isPrimitive() ? type : Object.class;
+        return 4 * MAX_WIDTH / typeToWidth.get(type);
+    }
+
+    static abstract class ArrayType<T> {
+        final Class<?> arrayType;
+        final Class<?> componentType;
+        final boolean unsigned;
+
+        final MethodHandle cpy;
+
+        final MethodHandle eq;
+        final MethodHandle eqr;
+        final MethodHandle cmp;
+        final MethodHandle cmpr;
+        final MethodHandle mm;
+        final MethodHandle mmr;
+
+        final MethodHandle getter;
+
+        final MethodHandle toString;
+
+        public ArrayType(Class<T> arrayType) {
+            this(arrayType, false);
+        }
+
+        public ArrayType(Class<T> arrayType, boolean unsigned) {
+            this.arrayType = arrayType;
+            this.componentType = arrayType.getComponentType();
+            this.unsigned = unsigned;
+
+            try {
+                MethodHandles.Lookup l = MethodHandles.lookup();
+
+                getter = MethodHandles.arrayElementGetter(arrayType);
+
+                if (componentType.isPrimitive()) {
+                    cpy = l.findStatic(Arrays.class, "copyOfRange",
+                            MethodType.methodType(arrayType, arrayType, int.class, int.class));
+
+                    MethodType eqt = MethodType.methodType(
+                            boolean.class, arrayType, arrayType);
+                    MethodType eqrt = MethodType.methodType(
+                            boolean.class, arrayType, int.class, int.class, arrayType, int.class, int.class);
+
+                    eq = l.findStatic(Arrays.class, "equals", eqt);
+                    eqr = l.findStatic(Arrays.class, "equals", eqrt);
+
+                    String compareName = unsigned ? "compareUnsigned" : "compare";
+                    cmp = l.findStatic(Arrays.class, compareName,
+                            eqt.changeReturnType(int.class));
+                    cmpr = l.findStatic(Arrays.class, compareName,
+                            eqrt.changeReturnType(int.class));
+
+                    mm = l.findStatic(Arrays.class, "mismatch",
+                            eqt.changeReturnType(int.class));
+                    mmr = l.findStatic(Arrays.class, "mismatch",
+                            eqrt.changeReturnType(int.class));
+
+                    toString = l.findStatic(Arrays.class, "toString",
+                            MethodType.methodType(String.class, arrayType));
+                }
+                else {
+                    cpy = l.findStatic(Arrays.class, "copyOfRange",
+                            MethodType.methodType(Object[].class, Object[].class, int.class, int.class));
+
+                    MethodType eqt = MethodType.methodType(
+                            boolean.class, Object[].class, Object[].class);
+                    MethodType eqrt = MethodType.methodType(
+                            boolean.class, Object[].class, int.class, int.class, Object[].class, int.class, int.class);
+
+                    eq = l.findStatic(Arrays.class, "equals", eqt);
+                    eqr = l.findStatic(Arrays.class, "equals", eqrt);
+
+                    MethodType cmpt = MethodType.methodType(
+                            int.class, Comparable[].class, Comparable[].class);
+                    MethodType cmprt = MethodType.methodType(
+                            int.class, Comparable[].class, int.class, int.class, Comparable[].class, int.class, int.class);
+
+                    cmp = l.findStatic(Arrays.class, "compare", cmpt);
+                    cmpr = l.findStatic(Arrays.class, "compare", cmprt);
+
+                    mm = l.findStatic(Arrays.class, "mismatch",
+                            eqt.changeReturnType(int.class));
+                    mmr = l.findStatic(Arrays.class, "mismatch",
+                            eqrt.changeReturnType(int.class));
+
+                    toString = l.findStatic(Arrays.class, "toString",
+                            MethodType.methodType(String.class, Object[].class));
+                }
+
+            }
+            catch (Exception e) {
+                throw new Error(e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            String s = arrayType.getCanonicalName();
+            return unsigned ? "unsigned " + s : s;
+        }
+
+        Object construct(int length) {
+            return Array.newInstance(componentType, length);
+        }
+
+        Object copyOf(Object a) {
+            return copyOf(a, 0, Array.getLength(a));
+        }
+
+        Object copyOf(Object a, int from, int to) {
+            try {
+                return (Object) cpy.invoke(a, from, to);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        Object get(Object a, int i) {
+            try {
+                return (Object) getter.invoke(a, i);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        abstract void set(Object a, int i, Object v);
+
+        boolean equals(Object a, Object b) {
+            try {
+                return (boolean) eq.invoke(a, b);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        boolean equals(Object a, int aFromIndex, int aToIndex,
+                Object b, int bFromIndex, int bToIndex) {
+            try {
+                return (boolean) eqr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        int compare(Object a, Object b) {
+            try {
+                return (int) cmp.invoke(a, b);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        int compare(Object a, int aFromIndex, int aToIndex,
+                Object b, int bFromIndex, int bToIndex) {
+            try {
+                return (int) cmpr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        int mismatch(Object a, Object b) {
+            try {
+                return (int) mm.invoke(a, b);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        int mismatch(Object a, int aFromIndex, int aToIndex,
+                Object b, int bFromIndex, int bToIndex) {
+            try {
+                return (int) mmr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        String toString(Object a) {
+            try {
+                return (String) toString.invoke(a);
+            }
+            catch (RuntimeException | Error e) {
+                throw e;
+            }
+            catch (Throwable t) {
+                throw new Error(t);
+            }
+        }
+
+        static class BoxedIntegers extends ArrayType<Integer[]> {
+            public BoxedIntegers() {
+                super(Integer[].class);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                // Ensure unique reference
+                ((Integer[]) a)[i] = v != null ? new Integer((Integer) v) : null;
+            }
+        }
+
+        static class BoxedIntegersWithReverseComparator extends BoxedIntegers {
+            final Comparator<Integer> c = (a, b) -> {
+                // Nulls sort after non-nulls
+                if (a == null || b == null)
+                    return a == null ? b == null ? 0 : 1 : -1;
+
+                return Integer.compare(b, a);
+            };
+
+            final MethodHandle eqc;
+            final MethodHandle eqcr;
+            final MethodHandle cmpc;
+            final MethodHandle cmpcr;
+            final MethodHandle mismatchc;
+            final MethodHandle mismatchcr;
+
+            public BoxedIntegersWithReverseComparator() {
+                try {
+                    MethodHandles.Lookup l = MethodHandles.lookup();
+
+                    MethodType cmpt = MethodType.methodType(
+                            int.class, Object[].class, Object[].class, Comparator.class);
+                    MethodType cmprt = MethodType.methodType(
+                            int.class, Object[].class, int.class, int.class,
+                            Object[].class, int.class, int.class, Comparator.class);
+
+                    eqc = l.findStatic(Arrays.class, "equals", cmpt.changeReturnType(boolean.class));
+                    eqcr = l.findStatic(Arrays.class, "equals", cmprt.changeReturnType(boolean.class));
+                    cmpc = l.findStatic(Arrays.class, "compare", cmpt);
+                    cmpcr = l.findStatic(Arrays.class, "compare", cmprt);
+                    mismatchc = l.findStatic(Arrays.class, "mismatch", cmpt);
+                    mismatchcr = l.findStatic(Arrays.class, "mismatch", cmprt);
+                }
+                catch (Exception e) {
+                    throw new Error(e);
+                }
+            }
+
+            @Override
+            boolean equals(Object a, Object b) {
+                try {
+                    return (boolean) eqc.invoke(a, b, c);
+                }
+                catch (RuntimeException | Error e) {
+                    throw e;
+                }
+                catch (Throwable t) {
+                    throw new Error(t);
+                }
+            }
+
+            @Override
+            boolean equals(Object a, int aFromIndex, int aToIndex,
+                    Object b, int bFromIndex, int bToIndex) {
+                try {
+                    return (boolean) eqcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);
+                }
+                catch (RuntimeException | Error e) {
+                    throw e;
+                }
+                catch (Throwable t) {
+                    throw new Error(t);
+                }
+            }
+
+            @Override
+            int compare(Object a, Object b) {
+                try {
+                    return (int) cmpc.invoke(a, b, c);
+                }
+                catch (RuntimeException | Error e) {
+                    throw e;
+                }
+                catch (Throwable t) {
+                    throw new Error(t);
+                }
+            }
+
+            @Override
+            int compare(Object a, int aFromIndex, int aToIndex,
+                    Object b, int bFromIndex, int bToIndex) {
+                try {
+                    return (int) cmpcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);
+                }
+                catch (RuntimeException | Error e) {
+                    throw e;
+                }
+                catch (Throwable t) {
+                    throw new Error(t);
+                }
+            }
+
+            @Override
+            int mismatch(Object a, Object b) {
+                try {
+                    return (int) mismatchc.invoke(a, b, c);
+                }
+                catch (RuntimeException | Error e) {
+                    throw e;
+                }
+                catch (Throwable t) {
+                    throw new Error(t);
+                }
+            }
+
+            @Override
+            int mismatch(Object a, int aFromIndex, int aToIndex,
+                    Object b, int bFromIndex, int bToIndex) {
+                try {
+                    return (int) mismatchcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);
+                }
+                catch (RuntimeException | Error e) {
+                    throw e;
+                }
+                catch (Throwable t) {
+                    throw new Error(t);
+                }
+            }
+
+            @Override
+            public String toString() {
+                return arrayType.getCanonicalName() + " with Comparator";
+            }
+        }
+
+        static class Booleans extends ArrayType<boolean[]> {
+            public Booleans() {
+                super(boolean[].class);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                boolean pv;
+                if (v instanceof Boolean) {
+                    pv = (Boolean) v;
+                }
+                else if (v instanceof Integer) {
+                    pv = ((Integer) v) >= 0;
+                }
+                else throw new IllegalStateException();
+
+                ((boolean[]) a)[i] = pv;
+            }
+        }
+
+        static class Bytes extends ArrayType<byte[]> {
+            public Bytes(boolean unsigned) {
+                super(byte[].class, unsigned);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                byte pv;
+                if (v instanceof Byte) {
+                    pv = (Byte) v;
+                }
+                else if (v instanceof Integer) {
+                    pv = ((Integer) v).byteValue();
+                }
+                else throw new IllegalStateException();
+
+                ((byte[]) a)[i] = pv;
+            }
+        }
+
+        static class Characters extends ArrayType<char[]> {
+            public Characters() {
+                super(char[].class);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                char pv;
+                if (v instanceof Character) {
+                    pv = (Character) v;
+                }
+                else if (v instanceof Integer) {
+                    pv = (char) ((Integer) v).intValue();
+                }
+                else throw new IllegalStateException();
+
+                ((char[]) a)[i] = pv;
+            }
+        }
+
+        static class Shorts extends ArrayType<short[]> {
+            public Shorts(boolean unsigned) {
+                super(short[].class, unsigned);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                short pv;
+                if (v instanceof Short) {
+                    pv = (Short) v;
+                }
+                else if (v instanceof Integer) {
+                    pv = ((Integer) v).shortValue();
+                }
+                else throw new IllegalStateException();
+
+                ((short[]) a)[i] = pv;
+            }
+        }
+
+        static class Integers extends ArrayType<int[]> {
+            public Integers(boolean unsigned) {
+                super(int[].class, unsigned);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                int pv;
+                if (v instanceof Integer) {
+                    pv = ((Integer) v).shortValue();
+                }
+                else throw new IllegalStateException();
+
+                ((int[]) a)[i] = pv;
+            }
+        }
+
+        static class Longs extends ArrayType<long[]> {
+            public Longs(boolean unsigned) {
+                super(long[].class, unsigned);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                long pv;
+                if (v instanceof Long) {
+                    pv = (Long) v;
+                }
+                else if (v instanceof Integer) {
+                    pv = ((Integer) v).longValue();
+                }
+                else throw new IllegalStateException();
+
+                ((long[]) a)[i] = pv;
+            }
+        }
+
+        static class Floats extends ArrayType<float[]> {
+            public Floats() {
+                super(float[].class);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                float pv;
+                if (v instanceof Float) {
+                    pv = (Float) v;
+                }
+                else if (v instanceof Integer) {
+                    pv = ((Integer) v).floatValue();
+                }
+                else throw new IllegalStateException();
+
+                ((float[]) a)[i] = pv;
+            }
+        }
+
+        static class Doubles extends ArrayType<double[]> {
+            public Doubles() {
+                super(double[].class);
+            }
+
+            @Override
+            void set(Object a, int i, Object v) {
+                double pv;
+                if (v instanceof Double) {
+                    pv = (Double) v;
+                }
+                else if (v instanceof Integer) {
+                    pv = ((Integer) v).doubleValue();
+                }
+                else throw new IllegalStateException();
+
+                ((double[]) a)[i] = pv;
+            }
+        }
+    }
+
+    static Object[][] arrayTypes;
+
+    @DataProvider
+    public static Object[][] arrayTypesProvider() {
+        if (arrayTypes == null) {
+            arrayTypes = new Object[][]{
+                    new Object[]{new ArrayType.BoxedIntegers()},
+                    new Object[]{new ArrayType.BoxedIntegersWithReverseComparator()},
+                    new Object[]{new ArrayType.Booleans()},
+                    new Object[]{new ArrayType.Bytes(false)},
+                    new Object[]{new ArrayType.Bytes(true)},
+                    new Object[]{new ArrayType.Characters()},
+                    new Object[]{new ArrayType.Shorts(false)},
+                    new Object[]{new ArrayType.Shorts(true)},
+                    new Object[]{new ArrayType.Integers(false)},
+                    new Object[]{new ArrayType.Integers(true)},
+                    new Object[]{new ArrayType.Longs(false)},
+                    new Object[]{new ArrayType.Longs(true)},
+                    new Object[]{new ArrayType.Floats()},
+                    new Object[]{new ArrayType.Doubles()},
+            };
+        }
+        return arrayTypes;
+    }
+
+    static Object[][] floatArrayTypes;
+
+    @DataProvider
+    public static Object[][] floatArrayTypesProvider() {
+        if (floatArrayTypes == null) {
+            LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);
+            LongFunction<Object> bToD = Double::longBitsToDouble;
+
+            floatArrayTypes = new Object[][]{
+                    new Object[]{new ArrayType.Floats(), 0x7fc00000L, 0x7f800001L, bTof},
+                    new Object[]{new ArrayType.Doubles(), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
+            };
+        }
+        return floatArrayTypes;
+    }
+
+    static Object[][] objectArrayTypes;
+
+    @DataProvider
+    public static Object[][] objectArrayTypesProvider() {
+        if (objectArrayTypes == null) {
+            LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);
+            LongFunction<Object> bToD = Double::longBitsToDouble;
+
+            objectArrayTypes = new Object[][]{
+                    new Object[]{new ArrayType.BoxedIntegers()},
+                    new Object[]{new ArrayType.BoxedIntegersWithReverseComparator()},
+            };
+        }
+        return objectArrayTypes;
+    }
+
+
+    static Object[][] signedUnsignedArrayTypes;
+
+    @DataProvider
+    public static Object[][] signedUnsignedArrayTypes() {
+        if (signedUnsignedArrayTypes == null) {
+            signedUnsignedArrayTypes = new Object[][]{
+                    new Object[]{new ArrayType.Bytes(false), new ArrayType.Bytes(true)},
+                    new Object[]{new ArrayType.Shorts(false), new ArrayType.Shorts(true)},
+                    new Object[]{new ArrayType.Integers(false), new ArrayType.Integers(true)},
+                    new Object[]{new ArrayType.Longs(false), new ArrayType.Longs(true)},
+            };
+        }
+        return signedUnsignedArrayTypes;
+    }
+
+    // Equality and comparison tests
+
+    @Test(dataProvider = "arrayTypesProvider")
+    public void testArray(ArrayType<?> arrayType) {
+        BiFunction<ArrayType<?>, Integer, Object> constructor = (at, s) -> {
+            Object a = at.construct(s);
+            for (int x = 0; x < s; x++) {
+                at.set(a, x, x % 8);
+            }
+            return a;
+        };
+
+        BiFunction<ArrayType<?>, Object, Object> cloner = (at, a) ->
+                constructor.apply(at, Array.getLength(a));
+
+        testArrayType(arrayType, constructor, cloner);
+    }
+
+    @Test(dataProvider = "floatArrayTypesProvider")
+    public void testPrimitiveFloatArray(
+            ArrayType<?> arrayType,
+            long canonicalNanRawBits, long nonCanonicalNanRawBits,
+            LongFunction<Object> bitsToFloat) {
+        Object canonicalNan = bitsToFloat.apply(canonicalNanRawBits);
+        // If conversion is a signalling NaN it may be subject to conversion to a
+        // quiet NaN on some processors, even if a copy is performed
+        // The tests assume that if conversion occurs it does not convert to the
+        // canonical NaN
+        Object nonCanonicalNan = bitsToFloat.apply(nonCanonicalNanRawBits);
+
+        BiFunction<ArrayType<?>, Integer, Object> canonicalNaNs = (at, s) -> {
+            Object a = at.construct(s);
+            for (int x = 0; x < s; x++) {
+                at.set(a, x, canonicalNan);
+            }
+            return a;
+        };
+
+        BiFunction<ArrayType<?>, Object, Object> nonCanonicalNaNs = (at, a) -> {
+            int s = Array.getLength(a);
+            Object ac = at.construct(s);
+            for (int x = 0; x < s; x++) {
+                at.set(ac, x, nonCanonicalNan);
+            }
+            return ac;
+        };
+
+        BiFunction<ArrayType<?>, Object, Object> halfNonCanonicalNaNs = (at, a) -> {
+            int s = Array.getLength(a);
+            Object ac = at.construct(s);
+            for (int x = 0; x < s / 2; x++) {
+                at.set(ac, x, nonCanonicalNan);
+            }
+            for (int x = s / 2; x < s; x++) {
+                at.set(ac, x, 1);
+            }
+            return ac;
+        };
+
+        testArrayType(arrayType, canonicalNaNs, nonCanonicalNaNs);
+        testArrayType(arrayType, canonicalNaNs, halfNonCanonicalNaNs);
+    }
+
+    @Test(dataProvider = "objectArrayTypesProvider")
+    public void testNullElementsInObjectArray(ArrayType<?> arrayType) {
+        BiFunction<ArrayType<?>, Object, Object> cloner = ArrayType::copyOf;
+
+        // All nulls
+        testArrayType(arrayType,
+                (at, s) -> {
+                    Object a = at.construct(s);
+                    for (int x = 0; x < s; x++) {
+                        at.set(a, x, null);
+                    }
+                    return a;
+                },
+                cloner);
+
+
+        // Some nulls
+        testArrayType(arrayType,
+                (at, s) -> {
+                    Object a = at.construct(s);
+                    for (int x = 0; x < s; x++) {
+                        int v = x % 8;
+                        at.set(a, x, v == 0 ? null : v);
+                    }
+                    return a;
+                },
+                cloner);
+
+        Integer[] a = new Integer[]{null, 0};
+        Integer[] b = new Integer[]{0, 0};
+        Assert.assertTrue(Arrays.compare(a, b) < 0);
+        Assert.assertTrue(Arrays.compare(b, a) > 0);
+    }
+
+    @Test(dataProvider = "objectArrayTypesProvider")
+    public void testSameRefElementsInObjectArray(ArrayType<?> arrayType) {
+        BiFunction<ArrayType<?>, Object, Object> cloner = ArrayType::copyOf;
+
+        // One ref
+        Integer one = 1;
+        testArrayType(arrayType,
+                (at, s) -> {
+                    Integer[] a = (Integer[]) at.construct(s);
+                    for (int x = 0; x < s; x++) {
+                        a[x] = one;
+                    }
+                    return a;
+                },
+                cloner);
+
+        // All ref
+        testArrayType(arrayType,
+                (at, s) -> {
+                    Integer[] a = (Integer[]) at.construct(s);
+                    for (int x = 0; x < s; x++) {
+                        a[x] = Integer.valueOf(s);
+                    }
+                    return a;
+                },
+                cloner);
+
+        // Some same ref
+        testArrayType(arrayType,
+                (at, s) -> {
+                    Integer[] a = (Integer[]) at.construct(s);
+                    for (int x = 0; x < s; x++) {
+                        int v = x % 8;
+                        a[x] = v == 1 ? one : new Integer(v);
+                    }
+                    return a;
+                },
+                cloner);
+    }
+
+    @Test(dataProvider = "signedUnsignedArrayTypes")
+    public void testSignedUnsignedArray(ArrayType<?> sat, ArrayType<?> uat) {
+        BiFunction<ArrayType<?>, Integer, Object> constructor = (at, s) -> {
+            Object a = at.construct(s);
+            for (int x = 0; x < s; x++) {
+                at.set(a, x, 1);
+            }
+            return a;
+        };
+
+        int n = arraySizeFor(sat.componentType);
+
+        for (int s : ranges(0, n)) {
+            Object a = constructor.apply(sat, s);
+
+            for (int aFrom : ranges(0, s)) {
+                for (int aTo : ranges(aFrom, s)) {
+                    int aLength = aTo - aFrom;
+
+                    if (aLength > 0) {
+                        for (int i = aFrom; i < aTo; i++) {
+                            Object ac = sat.copyOf(a);
+                            // Create common prefix with a length of i - aFrom
+                            sat.set(ac, i, -1);
+
+                            int sc = sat.compare(ac, aFrom, aTo, a, aFrom, aTo);
+                            int uc = uat.compare(ac, aFrom, aTo, a, aFrom, aTo);
+
+                            Assert.assertTrue(sc < 0);
+                            Assert.assertTrue(uc > 0);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    void testArrayType(ArrayType<?> at,
+            BiFunction<ArrayType<?>, Integer, Object> constructor,
+            BiFunction<ArrayType<?>, Object, Object> cloner) {
+        int n = arraySizeFor(at.componentType);
+
+        for (int s : ranges(0, n)) {
+            Object a = constructor.apply(at, s);
+            Object b = cloner.apply(at, a);
+
+            for (int aFrom : ranges(0, s)) {
+                for (int aTo : ranges(aFrom, s)) {
+                    int aLength = aTo - aFrom;
+
+                    for (int bFrom : ranges(0, s)) {
+                        for (int bTo : ranges(bFrom, s)) {
+                            int bLength = bTo - bFrom;
+
+                            Object anr = at.copyOf(a, aFrom, aTo);
+                            Object bnr = at.copyOf(b, bFrom, bTo);
+
+                            boolean eq = isEqual(at, a, aFrom, aTo, b, bFrom, bTo);
+                            Assert.assertEquals(at.equals(a, aFrom, aTo, b, bFrom, bTo), eq);
+                            Assert.assertEquals(at.equals(b, bFrom, bTo, a, aFrom, aTo), eq);
+                            Assert.assertEquals(at.equals(anr, bnr), eq);
+                            Assert.assertEquals(at.equals(bnr, anr), eq);
+                            if (eq) {
+                                Assert.assertEquals(at.compare(a, aFrom, aTo, b, bFrom, bTo), 0);
+                                Assert.assertEquals(at.compare(b, bFrom, bTo, a, aFrom, aTo), 0);
+                                Assert.assertEquals(at.compare(anr, bnr), 0);
+                                Assert.assertEquals(at.compare(bnr, anr), 0);
+
+                                Assert.assertEquals(at.mismatch(a, aFrom, aTo, b, bFrom, bTo), -1);
+                                Assert.assertEquals(at.mismatch(b, bFrom, bTo, a, aFrom, aTo), -1);
+                                Assert.assertEquals(at.mismatch(anr, bnr), -1);
+                                Assert.assertEquals(at.mismatch(bnr, anr), -1);
+                            }
+                            else {
+                                int aCb = at.compare(a, aFrom, aTo, b, bFrom, bTo);
+                                int bCa = at.compare(b, bFrom, bTo, a, aFrom, aTo);
+                                int v = Integer.signum(aCb) * Integer.signum(bCa);
+                                Assert.assertTrue(v == -1);
+
+                                int anrCbnr = at.compare(anr, bnr);
+                                int bnrCanr = at.compare(bnr, anr);
+                                Assert.assertEquals(anrCbnr, aCb);
+                                Assert.assertEquals(bnrCanr, bCa);
+
+
+                                int aMb = at.mismatch(a, aFrom, aTo, b, bFrom, bTo);
+                                int bMa = at.mismatch(b, bFrom, bTo, a, aFrom, aTo);
+                                int anrMbnr = at.mismatch(anr, bnr);
+                                int bnrManr = at.mismatch(bnr, anr);
+
+                                Assert.assertNotEquals(aMb, -1);
+                                Assert.assertEquals(aMb, bMa);
+                                Assert.assertNotEquals(anrMbnr, -1);
+                                Assert.assertEquals(anrMbnr, bnrManr);
+                                Assert.assertEquals(aMb, anrMbnr);
+                                Assert.assertEquals(bMa, bnrManr);
+
+                                // Common or proper prefix
+                                Assert.assertTrue(at.equals(a, aFrom, aFrom + aMb, b, bFrom, bFrom + aMb));
+                                if (aMb < Math.min(aLength, bLength)) {
+                                    // Common prefix
+                                    Assert.assertFalse(isEqual(at, a, aFrom + aMb, b, bFrom + aMb));
+                                }
+                            }
+                        }
+                    }
+
+                    if (aLength > 0) {
+                        for (int i = aFrom; i < aTo; i++) {
+                            Object ac = at.copyOf(a);
+                            // Create common prefix with a length of i - aFrom
+                            at.set(ac, i, -1);
+
+                            Object acnr = at.copyOf(ac, aFrom, aTo);
+                            Object anr = at.copyOf(a, aFrom, aTo);
+
+                            Assert.assertFalse(at.equals(ac, aFrom, aTo, a, aFrom, aTo));
+                            Assert.assertFalse(at.equals(acnr, anr));
+
+                            int acCa = at.compare(ac, aFrom, aTo, a, aFrom, aTo);
+                            int aCac = at.compare(a, aFrom, aTo, ac, aFrom, aTo);
+                            int v = Integer.signum(acCa) * Integer.signum(aCac);
+                            Assert.assertTrue(v == -1);
+
+                            int acnrCanr = at.compare(acnr, anr);
+                            int anrCacnr = at.compare(anr, acnr);
+                            Assert.assertEquals(acnrCanr, acCa);
+                            Assert.assertEquals(anrCacnr, aCac);
+
+
+                            int acMa = at.mismatch(ac, aFrom, aTo, a, aFrom, aTo);
+                            int aMac = at.mismatch(a, aFrom, aTo, ac, aFrom, aTo);
+                            Assert.assertEquals(acMa, aMac);
+                            Assert.assertEquals(acMa, i - aFrom);
+
+                            int acnrManr = at.mismatch(acnr, anr);
+                            int anrMacnr = at.mismatch(anr, acnr);
+                            Assert.assertEquals(acnrManr, anrMacnr);
+                            Assert.assertEquals(acnrManr, i - aFrom);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    static boolean isEqual(ArrayType<?> at, Object a, int aFromIndex, int aToIndex,
+            Object b, int bFromIndex, int bToIndex) {
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        for (int i = 0; i < aLength; i++) {
+            Object av = at.get(a, aFromIndex++);
+            Object bv = at.get(b, bFromIndex++);
+            if (!Objects.equals(av, bv)) return false;
+        }
+
+        return true;
+    }
+
+    static boolean isEqual(ArrayType<?> at, Object a, int aFrom, Object b, int bFrom) {
+        Object av = at.get(a, aFrom);
+        Object bv = at.get(b, bFrom);
+
+        return Objects.equals(av, bv);
+    }
+
+    static int[] ranges(int from, int to) {
+        int width = to - from;
+        switch (width) {
+            case 0:
+                return new int[]{};
+            case 1:
+                return new int[]{from, to};
+            case 2:
+                return new int[]{from, from + 1, to};
+            case 3:
+                return new int[]{from, from + 1, from + 2, to};
+            default:
+                return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to)
+                        .filter(i -> i >= from && i <= to)
+                        .distinct().toArray();
+        }
+    }
+
+
+    // Null array reference tests
+
+    @Test(dataProvider = "arrayTypesProvider")
+    public void testNullArrayRefs(ArrayType<?> arrayType) {
+        Object n = null;
+        Object a = arrayType.construct(0);
+
+        Assert.assertTrue(arrayType.equals(n, n));
+        Assert.assertFalse(arrayType.equals(n, a));
+        Assert.assertFalse(arrayType.equals(a, n));
+
+        Assert.assertEquals(arrayType.compare(n, n), 0);
+        Assert.assertTrue(arrayType.compare(n, a) < 0);
+        Assert.assertTrue(arrayType.compare(a, n) > 0);
+    }
+
+
+    // Exception throwing tests
+
+    @Test(dataProvider = "arrayTypesProvider")
+    public void testNPEs(ArrayType<?> arrayType) {
+        Object[] values = new Object[]{null, arrayType.construct(0)};
+
+        for (Object o1 : values) {
+            for (Object o2 : values) {
+                if (o1 != null && o2 != null)
+                    continue;
+
+                testNPE(() -> arrayType.equals(o1, 0, 0, o2, 0, 0));
+                testNPE(() -> arrayType.compare(o1, 0, 0, o2, 0, 0));
+                testNPE(() -> arrayType.mismatch(o1, o2));
+                testNPE(() -> arrayType.mismatch(o1, 0, 0, o2, 0, 0));
+            }
+        }
+    }
+
+    @Test
+    public void testObjectNPEs() {
+        String[][] values = new String[][]{null, new String[0]};
+        Comparator<String> c = String::compareTo;
+        Comparator[] cs = new Comparator[]{null, c};
+
+        for (String[] o1 : values) {
+            for (String[] o2 : values) {
+                for (Comparator o3 : cs) {
+                    if (o1 != null && o2 != null && o3 != null)
+                        continue;
+
+                    if (o3 == null) {
+                        testNPE(() -> Arrays.equals(o1, o2, o3));
+                        testNPE(() -> Arrays.compare(o1, o2, o3));
+                        testNPE(() -> Arrays.mismatch(o1, o2, o3));
+                    }
+
+                    testNPE(() -> Arrays.equals(o1, 0, 0, o2, 0, 0, o3));
+                    testNPE(() -> Arrays.compare(o1, 0, 0, o2, 0, 0, o3));
+                    testNPE(() -> Arrays.mismatch(o1, 0, 0, o2, 0, 0, o3));
+                }
+            }
+        }
+    }
+
+    @Test(dataProvider = "arrayTypesProvider")
+    public void testIAEs(ArrayType<?> arrayType) {
+        List<Integer> values = Arrays.asList(0, 1);
+
+        for (int s : values) {
+            Object a = arrayType.construct(s);
+
+            for (int o1 : values) {
+                for (int o2 : values) {
+                    if (o1 <= o2) continue;
+
+                    testIAE(() -> arrayType.equals(a, o1, 0, a, o2, 0));
+                    testIAE(() -> arrayType.compare(a, o1, 0, a, o2, 0));
+                    testIAE(() -> arrayType.mismatch(a, o1, 0, a, o2, 0));
+                }
+            }
+        }
+    }
+
+    @Test(dataProvider = "arrayTypesProvider")
+    public void testAIOBEs(ArrayType<?> arrayType) {
+        List<Integer> froms = Arrays.asList(-1, 0);
+
+        for (int s : Arrays.asList(0, 1)) {
+            List<Integer> tos = Arrays.asList(s, s + 1);
+            Object a = arrayType.construct(s);
+
+            for (int aFrom : froms) {
+                for (int aTo : tos) {
+                    for (int bFrom : froms) {
+                        for (int bTo : tos) {
+                            if (aFrom >= 0 && aTo <= s &&
+                                    bFrom >= 0 && bTo <= s) continue;
+
+                            testAIOBE(() -> arrayType.equals(a, aFrom, aTo, a, bFrom, bTo));
+                            testAIOBE(() -> arrayType.compare(a, aFrom, aTo, a, bFrom, bTo));
+                            testAIOBE(() -> arrayType.mismatch(a, aFrom, aTo, a, bFrom, bTo));
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    static void testNPE(Runnable r) {
+        testThrowable(r, NullPointerException.class);
+    }
+
+    static void testIAE(Runnable r) {
+        testThrowable(r, IllegalArgumentException.class);
+    }
+
+    static void testAIOBE(Runnable r) {
+        testThrowable(r, ArrayIndexOutOfBoundsException.class);
+    }
+
+    static void testThrowable(Runnable r, Class<? extends Throwable> expected) {
+        Throwable caught = null;
+        try {
+            r.run();
+        }
+        catch (Throwable t) {
+            caught = t;
+        }
+        Assert.assertNotNull(caught);
+        Assert.assertTrue(expected.isInstance(caught));
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/util/Collections/EnumerationAsIterator.java b/ojluni/src/test/java/util/Collections/EnumerationAsIterator.java
new file mode 100644
index 0000000..60cad8f
--- /dev/null
+++ b/ojluni/src/test/java/util/Collections/EnumerationAsIterator.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 test.java.util.Collections;
+
+/**
+ * @test
+ * @bug 8072726
+ * @summary Tests for Enumeration-to-Iterator conversion.
+ * @run testng EnumerationAsIterator
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+import static org.testng.Assert.*;
+
+@Test
+public class EnumerationAsIterator {
+    static Object[] of(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+        return new Object[]{description, s, exp};
+    }
+
+    static Object[] of(String description, Collection<?> c, Collection<?> exp) {
+        return of(description, () -> Collections.enumeration(c), exp);
+    }
+
+    /**
+     * A wrapper Enumeration that doesn't override the
+     * default method on Enumeration.
+     */
+    static <T> Enumeration<T> wrapInDefault(Enumeration<T> e) {
+        return new Enumeration<>() {
+            @Override
+            public boolean hasMoreElements() {
+                return e.hasMoreElements();
+            }
+
+            @Override
+            public T nextElement() {
+                return e.nextElement();
+            }
+        };
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> unmodifiable() {
+        return Arrays.asList(
+                of("Default-wrapped ArrayList",
+                        () -> wrapInDefault(
+                                Collections.enumeration(new ArrayList<>(Arrays.asList("a")))),
+                        Arrays.asList("a")),
+
+                of("Unmodifiable ArrayList",
+                        Collections.unmodifiableList(new ArrayList<>(Arrays.asList("a"))),
+                        Arrays.asList("a")),
+
+                of("Modifiable ArrayList",
+                        new ArrayList<>(Arrays.asList("a")),
+                        Arrays.asList("a"))
+        ).iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> others() {
+        return Arrays.asList(
+                of("Default Collections.emptyEnumeration()",
+                        () -> wrapInDefault(Collections.emptyEnumeration()),
+                        Collections.emptyList()),
+
+                of("Collections.emptyEnumeration()",
+                        Collections::emptyEnumeration,
+                        Collections.emptyList()),
+
+                of("Collections.emptyList()",
+                        Collections.emptyList(),
+                        Collections.emptyList()),
+
+                of("Collections.singletonList()",
+                        Collections.singletonList("a"),
+                        Collections.singletonList("a")),
+
+                of("Arrays.asList(...)",
+                        Arrays.asList("a", "b", "c"),
+                        Arrays.asList("a", "b", "c"))
+        ).iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> all() {
+        List<Object[]> all = new ArrayList<>();
+        unmodifiable().forEachRemaining(all::add);
+        others().forEachRemaining(all::add);
+        return all.iterator();
+    }
+
+    @Test(dataProvider = "all")
+    public void consumeByNext(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+        Iterator<?> i = s.get().asIterator();
+        int count = 0;
+        while (i.hasNext()) {
+            assertTrue(i.hasNext());
+
+            i.next();
+            count++;
+        }
+        assertEquals(count, exp.size());
+
+        assertFalse(i.hasNext());
+
+        try {
+            i.next();
+            fail();
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test(dataProvider = "all")
+    public void consumeByForEachRemaining(String description,
+            Supplier<Enumeration<?>> s,
+            Collection<?> exp) {
+        Iterator<?> i = s.get().asIterator();
+        AtomicInteger ai = new AtomicInteger();
+        i.forEachRemaining(e -> ai.getAndIncrement());
+        assertEquals(ai.get(), exp.size());
+        i.forEachRemaining(e -> ai.getAndIncrement());
+        assertEquals(ai.get(), exp.size());
+
+        assertFalse(i.hasNext());
+
+        try {
+            i.next();
+            fail();
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test(dataProvider = "all")
+    public void consumeByNextThenForEachRemaining(String description,
+            Supplier<Enumeration<?>> s,
+            Collection<?> exp) {
+        Iterator<?> i = s.get().asIterator();
+        AtomicInteger ai = new AtomicInteger();
+        if (i.hasNext()) {
+            i.next();
+            ai.getAndIncrement();
+        }
+        i.forEachRemaining(e -> ai.getAndIncrement());
+        assertEquals(ai.get(), exp.size());
+        i.forEachRemaining(e -> ai.getAndIncrement());
+        assertEquals(ai.get(), exp.size());
+
+        assertFalse(i.hasNext());
+
+        try {
+            i.next();
+            fail();
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test(dataProvider = "all")
+    public void contents(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+        assertEquals(copy(s.get()), exp);
+    }
+
+    private List<?> copy(Enumeration<?> input) {
+        List<Object> output = new ArrayList<>();
+        input.asIterator().forEachRemaining(output::add);
+        return output;
+    }
+
+    @Test(dataProvider = "unmodifiable",
+            expectedExceptions=UnsupportedOperationException.class)
+    public void removeThrowsAfterAdvancingE(String description,
+            Supplier<Enumeration<?>> s,
+            Collection<?> exp) {
+        Enumeration<?> e = s.get();
+        e.nextElement();
+        e.asIterator().remove();
+    }
+
+    @Test(dataProvider = "unmodifiable",
+            expectedExceptions=UnsupportedOperationException.class)
+    public void removeThrowsAfterAdvancingI(String description,
+            Supplier<Enumeration<?>> s,
+            Collection<?> exp) {
+        Iterator<?> i = s.get().asIterator();
+        i.next();
+        i.remove();
+    }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java b/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
index e97a0ab..ada751c 100644
--- a/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
+++ b/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
@@ -170,7 +170,7 @@
         assertFalse(f.isCancelled());
         assertTrue(f.isDone());
         assertTrue(f.isCompletedExceptionally());
-        assertTrue(f.toString().contains("[Completed exceptionally]"));
+        assertTrue(f.toString().contains("[Completed exceptionally:"));
     }
 
     void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
@@ -225,7 +225,7 @@
         assertTrue(f.isDone());
         assertTrue(f.isCompletedExceptionally());
         assertTrue(f.isCancelled());
-        assertTrue(f.toString().contains("[Completed exceptionally]"));
+        assertTrue(f.toString().contains("[Completed exceptionally:"));
     }
 
     /**
@@ -372,12 +372,12 @@
 
         f = new CompletableFuture<String>();
         assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
-        assertTrue(f.toString().contains("[Completed exceptionally]"));
+        assertTrue(f.toString().contains("[Completed exceptionally:"));
 
         for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
             f = new CompletableFuture<String>();
             assertTrue(f.cancel(mayInterruptIfRunning));
-            assertTrue(f.toString().contains("[Completed exceptionally]"));
+            assertTrue(f.toString().contains("[Completed exceptionally:"));
         }
     }
 
diff --git a/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java b/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
index 575a8f3..f821a3b 100644
--- a/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
+++ b/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
@@ -590,6 +590,7 @@
                 "AtomicReferenceArray9Test",
                 "ExecutorCompletionService9Test",
                 "ForkJoinPool9Test",
+                "SubmissionPublisherTest",
             };
             addNamedTestClasses(suite, java9TestClassNames);
         }
diff --git a/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java b/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java
new file mode 100644
index 0000000..bfdecbe
--- /dev/null
+++ b/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java
@@ -0,0 +1,1036 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package test.java.util.concurrent.tck;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Flow;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.SubmissionPublisher;
+import java.util.concurrent.atomic.AtomicInteger;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import static java.util.concurrent.Flow.Subscriber;
+import static java.util.concurrent.Flow.Subscription;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class SubmissionPublisherTest extends JSR166TestCase {
+
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+    public static Test suite() {
+        return new TestSuite(SubmissionPublisherTest.class);
+    }
+
+    final Executor basicExecutor = basicPublisher().getExecutor();
+
+    static SubmissionPublisher<Integer> basicPublisher() {
+        return new SubmissionPublisher<Integer>();
+    }
+
+    static class SPException extends RuntimeException {}
+
+    class TestSubscriber implements Subscriber<Integer> {
+        volatile Subscription sn;
+        int last;  // Requires that onNexts are in numeric order
+        volatile int nexts;
+        volatile int errors;
+        volatile int completes;
+        volatile boolean throwOnCall = false;
+        volatile boolean request = true;
+        volatile Throwable lastError;
+
+        public synchronized void onSubscribe(Subscription s) {
+            threadAssertTrue(sn == null);
+            sn = s;
+            notifyAll();
+            if (throwOnCall)
+                throw new SPException();
+            if (request)
+                sn.request(1L);
+        }
+        public synchronized void onNext(Integer t) {
+            ++nexts;
+            notifyAll();
+            int current = t.intValue();
+            threadAssertTrue(current >= last);
+            last = current;
+            if (request)
+                sn.request(1L);
+            if (throwOnCall)
+                throw new SPException();
+        }
+        public synchronized void onError(Throwable t) {
+            threadAssertTrue(completes == 0);
+            threadAssertTrue(errors == 0);
+            lastError = t;
+            ++errors;
+            notifyAll();
+        }
+        public synchronized void onComplete() {
+            threadAssertTrue(completes == 0);
+            ++completes;
+            notifyAll();
+        }
+
+        synchronized void awaitSubscribe() {
+            while (sn == null) {
+                try {
+                    wait();
+                } catch (Exception ex) {
+                    threadUnexpectedException(ex);
+                    break;
+                }
+            }
+        }
+        synchronized void awaitNext(int n) {
+            while (nexts < n) {
+                try {
+                    wait();
+                } catch (Exception ex) {
+                    threadUnexpectedException(ex);
+                    break;
+                }
+            }
+        }
+        synchronized void awaitComplete() {
+            while (completes == 0 && errors == 0) {
+                try {
+                    wait();
+                } catch (Exception ex) {
+                    threadUnexpectedException(ex);
+                    break;
+                }
+            }
+        }
+        synchronized void awaitError() {
+            while (errors == 0) {
+                try {
+                    wait();
+                } catch (Exception ex) {
+                    threadUnexpectedException(ex);
+                    break;
+                }
+            }
+        }
+
+    }
+
+    /**
+     * A new SubmissionPublisher has no subscribers, a non-null
+     * executor, a power-of-two capacity, is not closed, and reports
+     * zero demand and lag
+     */
+    void checkInitialState(SubmissionPublisher<?> p) {
+        assertFalse(p.hasSubscribers());
+        assertEquals(0, p.getNumberOfSubscribers());
+        assertTrue(p.getSubscribers().isEmpty());
+        assertFalse(p.isClosed());
+        assertNull(p.getClosedException());
+        int n = p.getMaxBufferCapacity();
+        assertTrue((n & (n - 1)) == 0); // power of two
+        assertNotNull(p.getExecutor());
+        assertEquals(0, p.estimateMinimumDemand());
+        assertEquals(0, p.estimateMaximumLag());
+    }
+
+    /**
+     * A default-constructed SubmissionPublisher has no subscribers,
+     * is not closed, has default buffer size, and uses the
+     * defaultExecutor
+     */
+    public void testConstructor1() {
+        SubmissionPublisher<Integer> p = new SubmissionPublisher<>();
+        checkInitialState(p);
+        assertEquals(p.getMaxBufferCapacity(), Flow.defaultBufferSize());
+        Executor e = p.getExecutor(), c = ForkJoinPool.commonPool();
+        if (ForkJoinPool.getCommonPoolParallelism() > 1)
+            assertSame(e, c);
+        else
+            assertNotSame(e, c);
+    }
+
+    /**
+     * A new SubmissionPublisher has no subscribers, is not closed,
+     * has the given buffer size, and uses the given executor
+     */
+    public void testConstructor2() {
+        Executor e = Executors.newFixedThreadPool(1);
+        SubmissionPublisher<Integer> p = new SubmissionPublisher<>(e, 8);
+        checkInitialState(p);
+        assertSame(p.getExecutor(), e);
+        assertEquals(8, p.getMaxBufferCapacity());
+    }
+
+    /**
+     * A null Executor argument to SubmissionPublisher constructor
+     * throws NullPointerException
+     */
+    public void testConstructor3() {
+        try {
+            new SubmissionPublisher<Integer>(null, 8);
+            shouldThrow();
+        } catch (NullPointerException success) {}
+    }
+
+    /**
+     * A negative capacity argument to SubmissionPublisher constructor
+     * throws IllegalArgumentException
+     */
+    public void testConstructor4() {
+        Executor e = Executors.newFixedThreadPool(1);
+        try {
+            new SubmissionPublisher<Integer>(e, -1);
+            shouldThrow();
+        } catch (IllegalArgumentException success) {}
+    }
+
+    /**
+     * A closed publisher reports isClosed with no closedException and
+     * throws IllegalStateException upon attempted submission; a
+     * subsequent close or closeExceptionally has no additional
+     * effect.
+     */
+    public void testClose() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        checkInitialState(p);
+        p.close();
+        assertTrue(p.isClosed());
+        assertNull(p.getClosedException());
+        try {
+            p.submit(1);
+            shouldThrow();
+        } catch (IllegalStateException success) {}
+        Throwable ex = new SPException();
+        p.closeExceptionally(ex);
+        assertTrue(p.isClosed());
+        assertNull(p.getClosedException());
+    }
+
+    /**
+     * A publisher closedExceptionally reports isClosed with the
+     * closedException and throws IllegalStateException upon attempted
+     * submission; a subsequent close or closeExceptionally has no
+     * additional effect.
+     */
+    public void testCloseExceptionally() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        checkInitialState(p);
+        Throwable ex = new SPException();
+        p.closeExceptionally(ex);
+        assertTrue(p.isClosed());
+        assertSame(p.getClosedException(), ex);
+        try {
+            p.submit(1);
+            shouldThrow();
+        } catch (IllegalStateException success) {}
+        p.close();
+        assertTrue(p.isClosed());
+        assertSame(p.getClosedException(), ex);
+    }
+
+    /**
+     * Upon subscription, the subscriber's onSubscribe is called, no
+     * other Subscriber methods are invoked, the publisher
+     * hasSubscribers, isSubscribed is true, and existing
+     * subscriptions are unaffected.
+     */
+    public void testSubscribe1() {
+        TestSubscriber s = new TestSubscriber();
+        SubmissionPublisher<Integer> p = basicPublisher();
+        p.subscribe(s);
+        assertTrue(p.hasSubscribers());
+        assertEquals(1, p.getNumberOfSubscribers());
+        assertTrue(p.getSubscribers().contains(s));
+        assertTrue(p.isSubscribed(s));
+        s.awaitSubscribe();
+        assertNotNull(s.sn);
+        assertEquals(0, s.nexts);
+        assertEquals(0, s.errors);
+        assertEquals(0, s.completes);
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s2);
+        assertTrue(p.hasSubscribers());
+        assertEquals(2, p.getNumberOfSubscribers());
+        assertTrue(p.getSubscribers().contains(s));
+        assertTrue(p.getSubscribers().contains(s2));
+        assertTrue(p.isSubscribed(s));
+        assertTrue(p.isSubscribed(s2));
+        s2.awaitSubscribe();
+        assertNotNull(s2.sn);
+        assertEquals(0, s2.nexts);
+        assertEquals(0, s2.errors);
+        assertEquals(0, s2.completes);
+        p.close();
+    }
+
+    /**
+     * If closed, upon subscription, the subscriber's onComplete
+     * method is invoked
+     */
+    public void testSubscribe2() {
+        TestSubscriber s = new TestSubscriber();
+        SubmissionPublisher<Integer> p = basicPublisher();
+        p.close();
+        p.subscribe(s);
+        s.awaitComplete();
+        assertEquals(0, s.nexts);
+        assertEquals(0, s.errors);
+        assertEquals(1, s.completes, 1);
+    }
+
+    /**
+     * If closedExceptionally, upon subscription, the subscriber's
+     * onError method is invoked
+     */
+    public void testSubscribe3() {
+        TestSubscriber s = new TestSubscriber();
+        SubmissionPublisher<Integer> p = basicPublisher();
+        Throwable ex = new SPException();
+        p.closeExceptionally(ex);
+        assertTrue(p.isClosed());
+        assertSame(p.getClosedException(), ex);
+        p.subscribe(s);
+        s.awaitError();
+        assertEquals(0, s.nexts);
+        assertEquals(1, s.errors);
+    }
+
+    /**
+     * Upon attempted resubscription, the subscriber's onError is
+     * called and the subscription is cancelled.
+     */
+    public void testSubscribe4() {
+        TestSubscriber s = new TestSubscriber();
+        SubmissionPublisher<Integer> p = basicPublisher();
+        p.subscribe(s);
+        assertTrue(p.hasSubscribers());
+        assertEquals(1, p.getNumberOfSubscribers());
+        assertTrue(p.getSubscribers().contains(s));
+        assertTrue(p.isSubscribed(s));
+        s.awaitSubscribe();
+        assertNotNull(s.sn);
+        assertEquals(0, s.nexts);
+        assertEquals(0, s.errors);
+        assertEquals(0, s.completes);
+        p.subscribe(s);
+        s.awaitError();
+        assertEquals(0, s.nexts);
+        assertEquals(1, s.errors);
+        assertFalse(p.isSubscribed(s));
+    }
+
+    /**
+     * An exception thrown in onSubscribe causes onError
+     */
+    public void testSubscribe5() {
+        TestSubscriber s = new TestSubscriber();
+        SubmissionPublisher<Integer> p = basicPublisher();
+        s.throwOnCall = true;
+        p.subscribe(s);
+        s.awaitError();
+        assertEquals(0, s.nexts);
+        assertEquals(1, s.errors);
+        assertEquals(0, s.completes);
+    }
+
+    /**
+     * subscribe(null) throws NPE
+     */
+    public void testSubscribe6() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        try {
+            p.subscribe(null);
+            shouldThrow();
+        } catch (NullPointerException success) {}
+        checkInitialState(p);
+    }
+
+    /**
+     * Closing a publisher causes onComplete to subscribers
+     */
+    public void testCloseCompletes() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        p.submit(1);
+        p.close();
+        assertTrue(p.isClosed());
+        assertNull(p.getClosedException());
+        s1.awaitComplete();
+        assertEquals(1, s1.nexts);
+        assertEquals(1, s1.completes);
+        s2.awaitComplete();
+        assertEquals(1, s2.nexts);
+        assertEquals(1, s2.completes);
+    }
+
+    /**
+     * Closing a publisher exceptionally causes onError to subscribers
+     * after they are subscribed
+     */
+    public void testCloseExceptionallyError() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        p.submit(1);
+        p.closeExceptionally(new SPException());
+        assertTrue(p.isClosed());
+        s1.awaitSubscribe();
+        s1.awaitError();
+        assertTrue(s1.nexts <= 1);
+        assertEquals(1, s1.errors);
+        s2.awaitSubscribe();
+        s2.awaitError();
+        assertTrue(s2.nexts <= 1);
+        assertEquals(1, s2.errors);
+    }
+
+    /**
+     * Cancelling a subscription eventually causes no more onNexts to be issued
+     */
+    public void testCancel() {
+        SubmissionPublisher<Integer> p =
+            new SubmissionPublisher<>(basicExecutor, 4); // must be < 20
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s1.awaitSubscribe();
+        p.submit(1);
+        s1.sn.cancel();
+        for (int i = 2; i <= 20; ++i)
+            p.submit(i);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(20, s2.nexts);
+        assertEquals(1, s2.completes);
+        assertTrue(s1.nexts < 20);
+        assertFalse(p.isSubscribed(s1));
+    }
+
+    /**
+     * Throwing an exception in onNext causes onError
+     */
+    public void testThrowOnNext() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s1.awaitSubscribe();
+        p.submit(1);
+        s1.throwOnCall = true;
+        p.submit(2);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(2, s2.nexts);
+        s1.awaitComplete();
+        assertEquals(1, s1.errors);
+    }
+
+    /**
+     * If a handler is supplied in constructor, it is invoked when
+     * subscriber throws an exception in onNext
+     */
+    public void testThrowOnNextHandler() {
+        AtomicInteger calls = new AtomicInteger();
+        SubmissionPublisher<Integer> p = new SubmissionPublisher<>(
+            basicExecutor, 8, (s, e) -> calls.getAndIncrement());
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s1.awaitSubscribe();
+        p.submit(1);
+        s1.throwOnCall = true;
+        p.submit(2);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(2, s2.nexts);
+        assertEquals(1, s2.completes);
+        s1.awaitError();
+        assertEquals(1, s1.errors);
+        assertEquals(1, calls.get());
+    }
+
+    /**
+     * onNext items are issued in the same order to each subscriber
+     */
+    public void testOrder() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        for (int i = 1; i <= 20; ++i)
+            p.submit(i);
+        p.close();
+        s2.awaitComplete();
+        s1.awaitComplete();
+        assertEquals(20, s2.nexts);
+        assertEquals(1, s2.completes);
+        assertEquals(20, s1.nexts);
+        assertEquals(1, s1.completes);
+    }
+
+    /**
+     * onNext is issued only if requested
+     */
+    public void testRequest1() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        p.subscribe(s1);
+        s1.awaitSubscribe();
+        assertEquals(0, p.estimateMinimumDemand());
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s2);
+        p.submit(1);
+        p.submit(2);
+        s2.awaitNext(1);
+        assertEquals(0, s1.nexts);
+        s1.sn.request(3);
+        p.submit(3);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(3, s2.nexts);
+        assertEquals(1, s2.completes);
+        s1.awaitComplete();
+        assertTrue(s1.nexts > 0);
+        assertEquals(1, s1.completes);
+    }
+
+    /**
+     * onNext is not issued when requests become zero
+     */
+    public void testRequest2() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        s1.request = false;
+        p.submit(1);
+        p.submit(2);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(2, s2.nexts);
+        assertEquals(1, s2.completes);
+        s1.awaitNext(1);
+        assertEquals(1, s1.nexts);
+    }
+
+    /**
+     * Non-positive request causes error
+     */
+    public void testRequest3() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        TestSubscriber s3 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        p.subscribe(s3);
+        s3.awaitSubscribe();
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        s1.sn.request(-1L);
+        s3.sn.request(0L);
+        p.submit(1);
+        p.submit(2);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(2, s2.nexts);
+        assertEquals(1, s2.completes);
+        s1.awaitError();
+        assertEquals(1, s1.errors);
+        assertTrue(s1.lastError instanceof IllegalArgumentException);
+        s3.awaitError();
+        assertEquals(1, s3.errors);
+        assertTrue(s3.lastError instanceof IllegalArgumentException);
+    }
+
+    /**
+     * estimateMinimumDemand reports 0 until request, nonzero after
+     * request
+     */
+    public void testEstimateMinimumDemand() {
+        TestSubscriber s = new TestSubscriber();
+        SubmissionPublisher<Integer> p = basicPublisher();
+        s.request = false;
+        p.subscribe(s);
+        s.awaitSubscribe();
+        assertEquals(0, p.estimateMinimumDemand());
+        s.sn.request(1);
+        assertEquals(1, p.estimateMinimumDemand());
+    }
+
+    /**
+     * submit to a publisher with no subscribers returns lag 0
+     */
+    public void testEmptySubmit() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        assertEquals(0, p.submit(1));
+    }
+
+    /**
+     * submit(null) throws NPE
+     */
+    public void testNullSubmit() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        try {
+            p.submit(null);
+            shouldThrow();
+        } catch (NullPointerException success) {}
+    }
+
+    /**
+     * submit returns number of lagged items, compatible with result
+     * of estimateMaximumLag.
+     */
+    public void testLaggedSubmit() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        assertEquals(1, p.submit(1));
+        assertTrue(p.estimateMaximumLag() >= 1);
+        assertTrue(p.submit(2) >= 2);
+        assertTrue(p.estimateMaximumLag() >= 2);
+        s1.sn.request(4);
+        assertTrue(p.submit(3) >= 3);
+        assertTrue(p.estimateMaximumLag() >= 3);
+        s2.sn.request(4);
+        p.submit(4);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(4, s2.nexts);
+        s1.awaitComplete();
+        assertEquals(4, s2.nexts);
+    }
+
+    /**
+     * submit eventually issues requested items when buffer capacity is 1
+     */
+    public void testCap1Submit() {
+        SubmissionPublisher<Integer> p
+            = new SubmissionPublisher<>(basicExecutor, 1);
+        TestSubscriber s1 = new TestSubscriber();
+        TestSubscriber s2 = new TestSubscriber();
+        p.subscribe(s1);
+        p.subscribe(s2);
+        for (int i = 1; i <= 20; ++i) {
+            assertTrue(p.submit(i) >= 0);
+        }
+        p.close();
+        s2.awaitComplete();
+        s1.awaitComplete();
+        assertEquals(20, s2.nexts);
+        assertEquals(1, s2.completes);
+        assertEquals(20, s1.nexts);
+        assertEquals(1, s1.completes);
+    }
+
+    static boolean noopHandle(AtomicInteger count) {
+        count.getAndIncrement();
+        return false;
+    }
+
+    static boolean reqHandle(AtomicInteger count, Subscriber s) {
+        count.getAndIncrement();
+        ((TestSubscriber)s).sn.request(Long.MAX_VALUE);
+        return true;
+    }
+
+    /**
+     * offer to a publisher with no subscribers returns lag 0
+     */
+    public void testEmptyOffer() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        assertEquals(0, p.offer(1, null));
+    }
+
+    /**
+     * offer(null) throws NPE
+     */
+    public void testNullOffer() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        try {
+            p.offer(null, null);
+            shouldThrow();
+        } catch (NullPointerException success) {}
+    }
+
+    /**
+     * offer returns number of lagged items if not saturated
+     */
+    public void testLaggedOffer() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        assertTrue(p.offer(1, null) >= 1);
+        assertTrue(p.offer(2, null) >= 2);
+        s1.sn.request(4);
+        assertTrue(p.offer(3, null) >= 3);
+        s2.sn.request(4);
+        p.offer(4, null);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(4, s2.nexts);
+        s1.awaitComplete();
+        assertEquals(4, s2.nexts);
+    }
+
+    /**
+     * offer reports drops if saturated
+     */
+    public void testDroppedOffer() {
+        SubmissionPublisher<Integer> p
+            = new SubmissionPublisher<>(basicExecutor, 4);
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        for (int i = 1; i <= 4; ++i)
+            assertTrue(p.offer(i, null) >= 0);
+        p.offer(5, null);
+        assertTrue(p.offer(6, null) < 0);
+        s1.sn.request(64);
+        assertTrue(p.offer(7, null) < 0);
+        s2.sn.request(64);
+        p.close();
+        s2.awaitComplete();
+        assertTrue(s2.nexts >= 4);
+        s1.awaitComplete();
+        assertTrue(s1.nexts >= 4);
+    }
+
+    /**
+     * offer invokes drop handler if saturated
+     */
+    public void testHandledDroppedOffer() {
+        AtomicInteger calls = new AtomicInteger();
+        SubmissionPublisher<Integer> p
+            = new SubmissionPublisher<>(basicExecutor, 4);
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        for (int i = 1; i <= 4; ++i)
+            assertTrue(p.offer(i, (s, x) -> noopHandle(calls)) >= 0);
+        p.offer(4, (s, x) -> noopHandle(calls));
+        assertTrue(p.offer(6, (s, x) -> noopHandle(calls)) < 0);
+        s1.sn.request(64);
+        assertTrue(p.offer(7, (s, x) -> noopHandle(calls)) < 0);
+        s2.sn.request(64);
+        p.close();
+        s2.awaitComplete();
+        s1.awaitComplete();
+        assertTrue(calls.get() >= 4);
+    }
+
+    /**
+     * offer succeeds if drop handler forces request
+     */
+    public void testRecoveredHandledDroppedOffer() {
+        AtomicInteger calls = new AtomicInteger();
+        SubmissionPublisher<Integer> p
+            = new SubmissionPublisher<>(basicExecutor, 4);
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        int n = 0;
+        for (int i = 1; i <= 8; ++i) {
+            int d = p.offer(i, (s, x) -> reqHandle(calls, s));
+            n = n + 2 + (d < 0 ? d : 0);
+        }
+        p.close();
+        s2.awaitComplete();
+        s1.awaitComplete();
+        assertEquals(n, s1.nexts + s2.nexts);
+        assertTrue(calls.get() >= 2);
+    }
+
+    /**
+     * Timed offer to a publisher with no subscribers returns lag 0
+     */
+    public void testEmptyTimedOffer() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        long startTime = System.nanoTime();
+        assertEquals(0, p.offer(1, LONG_DELAY_MS, MILLISECONDS, null));
+        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
+    }
+
+    /**
+     * Timed offer with null item or TimeUnit throws NPE
+     */
+    public void testNullTimedOffer() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        long startTime = System.nanoTime();
+        try {
+            p.offer(null, LONG_DELAY_MS, MILLISECONDS, null);
+            shouldThrow();
+        } catch (NullPointerException success) {}
+        try {
+            p.offer(1, LONG_DELAY_MS, null, null);
+            shouldThrow();
+        } catch (NullPointerException success) {}
+        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
+    }
+
+    /**
+     * Timed offer returns number of lagged items if not saturated
+     */
+    public void testLaggedTimedOffer() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        long startTime = System.nanoTime();
+        assertTrue(p.offer(1, LONG_DELAY_MS, MILLISECONDS, null) >= 1);
+        assertTrue(p.offer(2, LONG_DELAY_MS, MILLISECONDS, null) >= 2);
+        s1.sn.request(4);
+        assertTrue(p.offer(3, LONG_DELAY_MS, MILLISECONDS, null) >= 3);
+        s2.sn.request(4);
+        p.offer(4, LONG_DELAY_MS, MILLISECONDS, null);
+        p.close();
+        s2.awaitComplete();
+        assertEquals(4, s2.nexts);
+        s1.awaitComplete();
+        assertEquals(4, s2.nexts);
+        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
+    }
+
+    /**
+     * Timed offer reports drops if saturated
+     */
+    public void testDroppedTimedOffer() {
+        SubmissionPublisher<Integer> p
+            = new SubmissionPublisher<>(basicExecutor, 4);
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        long delay = timeoutMillis();
+        for (int i = 1; i <= 4; ++i)
+            assertTrue(p.offer(i, delay, MILLISECONDS, null) >= 0);
+        long startTime = System.nanoTime();
+        assertTrue(p.offer(5, delay, MILLISECONDS, null) < 0);
+        s1.sn.request(64);
+        assertTrue(p.offer(6, delay, MILLISECONDS, null) < 0);
+        // 2 * delay should elapse but check only 1 * delay to allow timer slop
+        assertTrue(millisElapsedSince(startTime) >= delay);
+        s2.sn.request(64);
+        p.close();
+        s2.awaitComplete();
+        assertTrue(s2.nexts >= 2);
+        s1.awaitComplete();
+        assertTrue(s1.nexts >= 2);
+    }
+
+    /**
+     * Timed offer invokes drop handler if saturated
+     */
+    public void testHandledDroppedTimedOffer() {
+        AtomicInteger calls = new AtomicInteger();
+        SubmissionPublisher<Integer> p
+            = new SubmissionPublisher<>(basicExecutor, 4);
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        long delay = timeoutMillis();
+        for (int i = 1; i <= 4; ++i)
+            assertTrue(p.offer(i, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) >= 0);
+        long startTime = System.nanoTime();
+        assertTrue(p.offer(5, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) < 0);
+        s1.sn.request(64);
+        assertTrue(p.offer(6, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) < 0);
+        assertTrue(millisElapsedSince(startTime) >= delay);
+        s2.sn.request(64);
+        p.close();
+        s2.awaitComplete();
+        s1.awaitComplete();
+        assertTrue(calls.get() >= 2);
+    }
+
+    /**
+     * Timed offer succeeds if drop handler forces request
+     */
+    public void testRecoveredHandledDroppedTimedOffer() {
+        AtomicInteger calls = new AtomicInteger();
+        SubmissionPublisher<Integer> p
+            = new SubmissionPublisher<>(basicExecutor, 4);
+        TestSubscriber s1 = new TestSubscriber();
+        s1.request = false;
+        TestSubscriber s2 = new TestSubscriber();
+        s2.request = false;
+        p.subscribe(s1);
+        p.subscribe(s2);
+        s2.awaitSubscribe();
+        s1.awaitSubscribe();
+        int n = 0;
+        long delay = timeoutMillis();
+        long startTime = System.nanoTime();
+        for (int i = 1; i <= 6; ++i) {
+            int d = p.offer(i, delay, MILLISECONDS, (s, x) -> reqHandle(calls, s));
+            n = n + 2 + (d < 0 ? d : 0);
+        }
+        assertTrue(millisElapsedSince(startTime) >= delay);
+        p.close();
+        s2.awaitComplete();
+        s1.awaitComplete();
+        assertEquals(n, s1.nexts + s2.nexts);
+        assertTrue(calls.get() >= 2);
+    }
+
+    /**
+     * consume returns a CompletableFuture that is done when
+     * publisher completes
+     */
+    public void testConsume() {
+        AtomicInteger sum = new AtomicInteger();
+        SubmissionPublisher<Integer> p = basicPublisher();
+        CompletableFuture<Void> f =
+            p.consume((Integer x) -> sum.getAndAdd(x.intValue()));
+        int n = 20;
+        for (int i = 1; i <= n; ++i)
+            p.submit(i);
+        p.close();
+        f.join();
+        assertEquals((n * (n + 1)) / 2, sum.get());
+    }
+
+    /**
+     * consume(null) throws NPE
+     */
+    public void testConsumeNPE() {
+        SubmissionPublisher<Integer> p = basicPublisher();
+        try {
+            CompletableFuture<Void> f = p.consume(null);
+            shouldThrow();
+        } catch (NullPointerException success) {}
+    }
+
+    /**
+     * consume eventually stops processing published items if cancelled
+     */
+    public void testCancelledConsume() {
+        AtomicInteger count = new AtomicInteger();
+        SubmissionPublisher<Integer> p = basicPublisher();
+        CompletableFuture<Void> f = p.consume(x -> count.getAndIncrement());
+        f.cancel(true);
+        int n = 1000000; // arbitrary limit
+        for (int i = 1; i <= n; ++i)
+            p.submit(i);
+        assertTrue(count.get() < n);
+    }
+
+    /**
+     * Tests scenario for
+     * JDK-8187947: A race condition in SubmissionPublisher
+     * cvs update -D '2017-11-25' src/main/java/util/concurrent/SubmissionPublisher.java && ant -Djsr166.expensiveTests=true -Djsr166.tckTestClass=SubmissionPublisherTest -Djsr166.methodFilter=testMissedSignal tck; cvs update -A src/main/java/util/concurrent/SubmissionPublisher.java
+     */
+    public void testMissedSignal_8187947() throws Exception {
+        if (!atLeastJava9()) return; // backport to jdk8 too hard
+        final int N = expensiveTests ? (1 << 20) : (1 << 10);
+        final CountDownLatch finished = new CountDownLatch(1);
+        final SubmissionPublisher<Boolean> pub = new SubmissionPublisher<>();
+        class Sub implements Subscriber<Boolean> {
+            int received;
+            public void onSubscribe(Subscription s) {
+                s.request(N);
+            }
+            public void onNext(Boolean item) {
+                if (++received == N)
+                    finished.countDown();
+                else
+                    CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE));
+            }
+            public void onError(Throwable t) { throw new AssertionError(t); }
+            public void onComplete() {}
+        }
+        pub.subscribe(new Sub());
+        CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE));
+        await(finished);
+    }
+}
diff --git a/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java b/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java
new file mode 100644
index 0000000..5cddf1c
--- /dev/null
+++ b/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package test.java.util.concurrent.tck;
+import static java.util.concurrent.TimeUnit.DAYS;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.LongStream;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class TimeUnit8Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        return new TestSuite(TimeUnit8Test.class);
+    }
+
+    /**
+     * tests for toChronoUnit.
+     */
+    public void testToChronoUnit() throws Exception {
+        assertSame(ChronoUnit.NANOS,   NANOSECONDS.toChronoUnit());
+        assertSame(ChronoUnit.MICROS,  MICROSECONDS.toChronoUnit());
+        assertSame(ChronoUnit.MILLIS,  MILLISECONDS.toChronoUnit());
+        assertSame(ChronoUnit.SECONDS, SECONDS.toChronoUnit());
+        assertSame(ChronoUnit.MINUTES, MINUTES.toChronoUnit());
+        assertSame(ChronoUnit.HOURS,   HOURS.toChronoUnit());
+        assertSame(ChronoUnit.DAYS,    DAYS.toChronoUnit());
+
+        // Every TimeUnit has a defined ChronoUnit equivalent
+        for (TimeUnit x : TimeUnit.values())
+            assertSame(x, TimeUnit.of(x.toChronoUnit()));
+    }
+
+    /**
+     * tests for TimeUnit.of(ChronoUnit).
+     */
+    public void testTimeUnitOf() throws Exception {
+        assertSame(NANOSECONDS,  TimeUnit.of(ChronoUnit.NANOS));
+        assertSame(MICROSECONDS, TimeUnit.of(ChronoUnit.MICROS));
+        assertSame(MILLISECONDS, TimeUnit.of(ChronoUnit.MILLIS));
+        assertSame(SECONDS,      TimeUnit.of(ChronoUnit.SECONDS));
+        assertSame(MINUTES,      TimeUnit.of(ChronoUnit.MINUTES));
+        assertSame(HOURS,        TimeUnit.of(ChronoUnit.HOURS));
+        assertSame(DAYS,         TimeUnit.of(ChronoUnit.DAYS));
+
+        assertThrows(NullPointerException.class,
+                     () -> TimeUnit.of((ChronoUnit)null));
+
+        // ChronoUnits either round trip to their TimeUnit
+        // equivalents, or throw IllegalArgumentException.
+        for (ChronoUnit cu : ChronoUnit.values()) {
+            final TimeUnit tu;
+            try {
+                tu = TimeUnit.of(cu);
+            } catch (IllegalArgumentException acceptable) {
+                continue;
+            }
+            assertSame(cu, tu.toChronoUnit());
+        }
+    }
+
+    /**
+     * convert(Duration) roundtrips with Duration.ofXXXX and Duration.of(long, ChronoUnit)
+     */
+    public void testConvertDuration_roundtripDurationOf() {
+        long n = ThreadLocalRandom.current().nextLong();
+
+        assertEquals(n, NANOSECONDS.convert(Duration.ofNanos(n)));
+        assertEquals(n, NANOSECONDS.convert(Duration.of(n, ChronoUnit.NANOS)));
+        assertEquals(n, MILLISECONDS.convert(Duration.ofMillis(n)));
+        assertEquals(n, MILLISECONDS.convert(Duration.of(n, ChronoUnit.MILLIS)));
+        assertEquals(n, SECONDS.convert(Duration.ofSeconds(n)));
+        assertEquals(n, SECONDS.convert(Duration.of(n, ChronoUnit.SECONDS)));
+        n /= 60;
+        assertEquals(n, MINUTES.convert(Duration.ofMinutes(n)));
+        assertEquals(n, MINUTES.convert(Duration.of(n, ChronoUnit.MINUTES)));
+        n /= 60;
+        assertEquals(n, HOURS.convert(Duration.ofHours(n)));
+        assertEquals(n, HOURS.convert(Duration.of(n, ChronoUnit.HOURS)));
+        n /= 24;
+        assertEquals(n, DAYS.convert(Duration.ofDays(n)));
+        assertEquals(n, DAYS.convert(Duration.of(n, ChronoUnit.DAYS)));
+    }
+
+    /**
+     * convert(Duration.ofNanos(n)) agrees with convert(n, NANOSECONDS)
+     */
+    public void testConvertDuration_roundtripDurationOfNanos() {
+        // Test values near unit transitions and near overflow.
+        LongStream.concat(
+                Arrays.stream(TimeUnit.values()).mapToLong(u -> u.toNanos(1)),
+                LongStream.of(Long.MAX_VALUE, Long.MIN_VALUE))
+            .flatMap(n -> LongStream.of(n, n + 1, n - 1))
+            .flatMap(n -> LongStream.of(n, n + 1_000_000_000, n - 1_000_000_000))
+            .flatMap(n -> LongStream.of(n, -n))
+            // .peek(System.err::println)
+            .forEach(n -> Arrays.stream(TimeUnit.values()).forEach(
+                u -> assertEquals(u.convert(n, NANOSECONDS),
+                                  u.convert(Duration.ofNanos(n)))));
+    }
+
+    /**
+     * convert(Duration) doesn't misbehave near Long.MAX_VALUE and Long.MIN_VALUE.
+     */
+    public void testConvertDuration_nearOverflow() {
+        ChronoUnit NANOS = ChronoUnit.NANOS;
+        Duration maxDuration = Duration.ofSeconds(Long.MAX_VALUE, 999_999_999);
+        Duration minDuration = Duration.ofSeconds(Long.MIN_VALUE, 0);
+
+        for (TimeUnit u : TimeUnit.values()) {
+            ChronoUnit cu = u.toChronoUnit();
+            long r;
+            if (u.toNanos(1) > SECONDS.toNanos(1)) {
+                r = u.toNanos(1) / SECONDS.toNanos(1);
+
+                assertThrows(ArithmeticException.class,
+                             () -> Duration.of(Long.MAX_VALUE, cu),
+                             () -> Duration.of(Long.MIN_VALUE, cu));
+            } else {
+                r = 1;
+
+                Duration max = Duration.of(Long.MAX_VALUE, cu);
+                Duration min = Duration.of(Long.MIN_VALUE, cu);
+                assertEquals(Long.MAX_VALUE, u.convert(max));
+                assertEquals(Long.MAX_VALUE - 1, u.convert(max.minus(1, NANOS)));
+                assertEquals(Long.MAX_VALUE - 1, u.convert(max.minus(1, cu)));
+                assertEquals(Long.MIN_VALUE, u.convert(min));
+                assertEquals(Long.MIN_VALUE + 1, u.convert(min.plus(1, NANOS)));
+                assertEquals(Long.MIN_VALUE + 1, u.convert(min.plus(1, cu)));
+                assertEquals(Long.MAX_VALUE, u.convert(max.plus(1, NANOS)));
+                if (u != SECONDS) {
+                    assertEquals(Long.MAX_VALUE, u.convert(max.plus(1, cu)));
+                    assertEquals(Long.MIN_VALUE, u.convert(min.minus(1, NANOS)));
+                    assertEquals(Long.MIN_VALUE, u.convert(min.minus(1, cu)));
+                }
+            }
+
+            assertEquals(Long.MAX_VALUE / r, u.convert(maxDuration));
+            assertEquals(Long.MIN_VALUE / r, u.convert(minDuration));
+        }
+    }
+
+}
diff --git a/openjdk_java_files.bp b/openjdk_java_files.bp
index ad34f44..7e6c9c8 100644
--- a/openjdk_java_files.bp
+++ b/openjdk_java_files.bp
@@ -589,6 +589,7 @@
         "ojluni/src/main/java/java/security/cert/PolicyNode.java",
         "ojluni/src/main/java/java/security/cert/PolicyQualifierInfo.java",
         "ojluni/src/main/java/java/security/cert/TrustAnchor.java",
+        "ojluni/src/main/java/java/security/cert/URICertStoreParameters.java",
         "ojluni/src/main/java/java/security/cert/X509Certificate.java",
         "ojluni/src/main/java/java/security/cert/X509CertSelector.java",
         "ojluni/src/main/java/java/security/cert/X509CRLEntry.java",
@@ -980,6 +981,7 @@
         "ojluni/src/main/java/java/util/concurrent/ScheduledFuture.java",
         "ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java",
         "ojluni/src/main/java/java/util/concurrent/Semaphore.java",
+        "ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java",
         "ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java",
         "ojluni/src/main/java/java/util/concurrent/ThreadFactory.java",
         "ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java",
@@ -1449,6 +1451,7 @@
         "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/HotSpotIntrinsicCandidate.java",
         "ojluni/src/main/java/jdk/internal/misc/JavaIOFileDescriptorAccess.java",
         "ojluni/src/main/java/jdk/internal/misc/JavaObjectInputStreamAccess.java",
         "ojluni/src/main/java/jdk/internal/misc/SharedSecrets.java",
@@ -1456,7 +1459,10 @@
         "ojluni/src/main/java/jdk/internal/misc/VM.java",
         "ojluni/src/main/java/jdk/internal/reflect/CallerSensitive.java",
         "ojluni/src/main/java/jdk/internal/reflect/Reflection.java",
+        "ojluni/src/main/java/jdk/internal/vm/annotation/Contended.java",
+        "ojluni/src/main/java/jdk/internal/vm/annotation/ReservedStackAccess.java",
         "ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java",
+        "ojluni/src/main/java/jdk/internal/util/ArraysSupport.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",
@@ -1707,6 +1713,7 @@
         "ojluni/src/main/java/sun/security/util/DerOutputStream.java",
         "ojluni/src/main/java/sun/security/util/DerValue.java",
         "ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java",
+        "ojluni/src/main/java/sun/security/util/HexDumpEncoder.java",
         "ojluni/src/main/java/sun/security/util/KeyUtil.java",
         "ojluni/src/main/java/sun/security/util/Length.java",
         "ojluni/src/main/java/sun/security/util/ManifestDigester.java",
diff --git a/tools/upstream/pkg-status b/tools/upstream/pkg-status
new file mode 100755
index 0000000..b8bc163
--- /dev/null
+++ b/tools/upstream/pkg-status
@@ -0,0 +1,428 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2021 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.
+
+"""
+Reports on merge status of Java files in a package based on four
+repositories:
+
+baseline - upstream baseline used for previous Android release
+release  - files in previous Android release
+current  - target for merge
+upstream - new upstream being merged
+
+Example output:
+$ tools/upstream/pkg-status java.security.spec
+AlgorithmParameterSpec.java: Unchanged, Done
+DSAGenParameterSpec.java: Added, TO DO
+DSAParameterSpec.java: Unchanged, Done
+DSAPrivateKeySpec.java: Unchanged, Done
+DSAPublicKeySpec.java: Unchanged, Done
+ECField.java: Unchanged, Done
+ECFieldF2m.java: Unchanged, Done
+ECFieldFp.java: Unchanged, Done
+ECGenParameterSpec.java: Updated, TO DO
+[...]
+"""
+
+import argparse
+import hashlib
+import os
+import os.path
+import sys
+from enum import Enum
+from pathlib import Path
+
+RED = '\u001b[31m'
+GREEN = "\u001b[32m"
+YELLOW = "\u001b[33m"
+RESET = "\u001b[0m"
+
+
+def colourise(colour, string):
+    """Wrap a string with an ANSI colour code"""
+    return "%s%s%s" % (colour, string, RESET)
+
+
+def red(string):
+    """Wrap a string with a red ANSI colour code"""
+    return colourise(RED, string)
+
+
+def green(string):
+    """Wrap a string with a green ANSI colour code"""
+    return colourise(GREEN, string)
+
+
+def yellow(string):
+    """Wrap a string with a yellow ANSI colour code"""
+    return colourise(YELLOW, string)
+
+
+class WorkStatus(Enum):
+    """Enum for a file's work completion status"""
+    UNKNOWN = ('Unknown', red)
+    TODO = ('TO DO', yellow)
+    DONE = ('Done', green)
+    PROBABLY_DONE = ('Probably done', green)
+    ERROR = ('Error', red)
+
+    def colourise(self, string):
+        """Colourise a string using the method for this enum value"""
+        return self.colourfunc(string)
+
+    def __init__(self, description, colourfunc):
+        self.description = description
+        self.colourfunc = colourfunc
+
+
+class MergeStatus(Enum):
+    """Enum for a file's merge status"""
+    UNKNOWN = 'Unknown!'
+    MISSING = 'Missing'
+    ADDED = 'Added'
+    DELETED = 'Deleted or moved'
+    UNCHANGED = 'Unchanged'
+    UPDATED = 'Updated'
+
+    def __init__(self, description):
+        self.description = description
+
+
+class MergeConfig:
+    """
+    Configuration for an upstream merge.
+
+    Encapsulates the paths to each of the required code repositories.
+    """
+    def __init__(self, baseline, release, current, upstream) -> None:
+        self.baseline = baseline
+        self.release = release
+        self.current = current
+        self.upstream = upstream
+        try:
+            # Root of checked-out Android sources, set by the "lunch" command.
+            self.android_build_top = os.environ['ANDROID_BUILD_TOP']
+            # Root of repository snapshots.
+            self.ojluni_upstreams = os.environ['OJLUNI_UPSTREAMS']
+        except KeyError:
+            sys.exit('`lunch` and set OJLUNI_UPSTREAMS first.')
+
+
+    def java_dir(self, repo, pkg):
+        relpath = pkg.replace('.', '/')
+        if repo == self.current:
+            return '%s/libcore/%s/src/main/java/%s' % (
+                    self.android_build_top, self.current, relpath)
+        else:
+            return '%s/%s/%s' % (self.ojluni_upstreams, repo, relpath)
+
+    def baseline_dir(self, pkg):
+        return self.java_dir(self.baseline, pkg)
+
+    def release_dir(self, pkg):
+        return self.java_dir(self.release, pkg)
+
+    def current_dir(self, pkg):
+        return self.java_dir(self.current, pkg)
+
+    def upstream_dir(self, pkg):
+        return self.java_dir(self.upstream, pkg)
+
+
+class JavaPackage:
+    """
+    Encapsulates information about a single Java package, notably paths
+    to it within each repository.
+    """
+    def __init__(self, config, name) -> None:
+        self.name = name
+        self.baseline_dir = config.baseline_dir(name)
+        self.release_dir = config.release_dir(name)
+        self.current_dir = config.current_dir(name)
+        self.upstream_dir = config.upstream_dir(name)
+
+    @staticmethod
+    def list_candidate_files(path):
+        """Returns a list of all the Java filenames in a directory."""
+        return list(filter(
+                lambda f: f.endswith('.java') and f != 'package-info.java',
+                os.listdir(path)))
+
+    def all_files(self):
+        """Returns the union of all the Java filenames in all repositories."""
+        files = set(self.list_candidate_files(self.baseline_dir))
+        files.update(self.list_candidate_files(self.release_dir))
+        files.update(self.list_candidate_files(self.upstream_dir))
+        files.update(self.list_candidate_files(self.current_dir))
+        return sorted(list(files))
+
+    def java_files(self):
+        """Returns a list of JavaFiles corresponding to all filenames."""
+        return map(lambda f: JavaFile(self, f), self.all_files())
+
+    def baseline_path(self, filename):
+        return Path(self.baseline_dir + '/' + filename)
+
+    def release_path(self, filename):
+        return Path(self.release_dir + '/' + filename)
+
+    def current_path(self, filename):
+        return Path(self.current_dir + '/' + filename)
+
+    def upstream_path(self, filename):
+        return Path(self.upstream_dir + '/' + filename)
+
+    def report_merge_status(self):
+        """Report on the mergse status of this package."""
+        for file in self.java_files():
+            merge_status, work_status = file.status()
+            text = '%s: %s, %s' % \
+                   (
+                           file.name, merge_status.description,
+                           work_status.description)
+            print(work_status.colourise(text))
+            if work_status == WorkStatus.ERROR:
+                print(file.baseline_sum, file.baseline)
+                print(file.release_sum, file.release)
+                print(file.current_sum, file.current)
+                print(file.upstream_sum, file.upstream)
+
+
+class JavaFile:
+    """
+    Encapsulates information about a single Java file in a package across
+    all of the repositories involved in a merge.
+    """
+    def __init__(self, package, name):
+        self.package = package
+        self.name = name
+        # Paths for this file in each repository
+        self.baseline = package.baseline_path(name)
+        self.release = package.release_path(name)
+        self.upstream = package.upstream_path(name)
+        self.current = package.current_path(name)
+        # Checksums for this file in each repository, or None if absent
+        self.baseline_sum = self.checksum(self.baseline)
+        self.release_sum = self.checksum(self.release)
+        self.upstream_sum = self.checksum(self.upstream)
+        self.current_sum = self.checksum(self.current)
+        # List of methods for determining file's merge status.
+        # Order matters - see merge_status() for details
+        self.merge_status_methods = [
+                (self.check_for_missing, MergeStatus.MISSING),
+                (self.check_for_unchanged, MergeStatus.UNCHANGED),
+                (self.check_for_added_upstream, MergeStatus.ADDED),
+                (self.check_for_removed_upstream, MergeStatus.DELETED),
+                (self.check_for_changed_upstream, MergeStatus.UPDATED),
+        ]
+        # Map of methods from merge status to determine work status
+        self.work_status_methods = {
+                MergeStatus.MISSING: self.calculate_missing_work_status,
+                MergeStatus.UNCHANGED: self.calculate_unchanged_work_status,
+                MergeStatus.ADDED: self.calculate_added_work_status,
+                MergeStatus.DELETED: self.calculate_deleted_work_status,
+                MergeStatus.UPDATED: self.calculate_updated_work_status,
+        }
+
+    def is_android_changed(self):
+        """
+        Returns true if the file was changed between the baseline and Android
+        release.
+        """
+        return self.is_in_release() and self.baseline_sum != self.release_sum
+
+    def is_android_unchanged(self):
+        """
+        Returns true if the file is in the Android release and is unchanged.
+        """
+        return self.is_in_release() and self.baseline_sum == self.release_sum
+
+    def check_for_changed_upstream(self):
+        """Returns true if the file is changed upstream since the baseline."""
+        return self.baseline_sum != self.upstream_sum
+
+    def is_in_baseline(self):
+        return self.baseline_sum is not None
+
+    def is_in_release(self):
+        """Returns true if the file is present in the baseline and release."""
+        return self.is_in_baseline() and self.release_sum is not None
+
+    def is_in_current(self):
+        """Returns true if the file is in current, release and baseline."""
+        return self.is_in_release() and self.current_sum is not None
+
+    def is_in_upstream(self):
+        return self.upstream_sum is not None
+
+    def check_for_missing(self):
+        """
+        Returns true if the file is expected to be in current, but isn't.
+        """
+        return self.is_in_release() and self.is_in_upstream() \
+               and not self.is_in_current()
+
+    def removed_in_release(self):
+        """Returns true if the file was removed by Android in the release."""
+        return self.is_in_baseline() and not self.is_in_release()
+
+    def check_for_removed_upstream(self):
+        """Returns true if the file was removed upstream since the baseline."""
+        return self.is_in_baseline() and not self.is_in_upstream()
+
+    def check_for_added_upstream(self):
+        """Returns true if the file was added upstream since the baseline."""
+        return self.is_in_upstream() and not self.is_in_baseline()
+
+    def check_for_unchanged(self):
+        """Returns true if the file is unchanged upstream since the baseline."""
+        return not self.check_for_changed_upstream()
+
+    def merge_status(self):
+        """
+        Returns the merge status for this file, or UNKNOWN.
+        Tries each merge_status_method in turn, and if one returns true
+        then this method returns the associated merge status.
+        """
+        for (method, status) in self.merge_status_methods:
+            if method():
+                return status
+        return MergeStatus.UNKNOWN
+
+    def work_status(self):
+        """
+        Returns the work status for this file.
+        Looks up a status method based on the merge statis and uses that to
+        determine the work status.
+        """
+        status = self.merge_status()
+        if status in self.work_status_methods:
+            return self.work_status_methods[status]()
+        return WorkStatus.ERROR
+
+    @staticmethod
+    def calculate_missing_work_status():
+        """Missing files are always an error."""
+        return WorkStatus.ERROR
+
+    def calculate_unchanged_work_status(self):
+        """
+        File is unchanged upstream, so should be unchanged between release and
+        current.
+        """
+        if self.current_sum == self.release_sum:
+            return WorkStatus.DONE
+        return WorkStatus.UNKNOWN
+
+    def calculate_added_work_status(self):
+        """File was added upstream so needs to be added to current."""
+        if self.current_sum is None:
+            return WorkStatus.TODO
+        if self.current_sum == self.upstream_sum:
+            return WorkStatus.DONE
+        #     XXX check for change markers if android changed
+        return WorkStatus.UNKNOWN
+
+    def calculate_deleted_work_status(self):
+        """File was removed upstream so needs to be removed from current."""
+        if self.is_in_current():
+            return WorkStatus.TODO
+        return WorkStatus.DONE
+
+    def calculate_updated_work_status(self):
+        """File was updated upstream."""
+        if self.current_sum == self.upstream_sum:
+            if self.is_android_unchanged():
+                return WorkStatus.DONE
+            # Looks like Android changes are missing in current
+            return WorkStatus.ERROR
+        if self.is_android_unchanged():
+            return WorkStatus.TODO
+        # If we get here there are upstream and Android changes that need
+        # to be merged,  If possible use the file copyright date as a
+        # heuristic to determine if upstream has been merged into current
+        release_copyright = self.get_copyright(self.release)
+        current_copyright = self.get_copyright(self.current)
+        upstream_copyright = self.get_copyright(self.upstream)
+        if release_copyright == upstream_copyright:
+            # Upstream copyright same as last release, so can't infer anything
+            return WorkStatus.UNKNOWN
+        if current_copyright == upstream_copyright:
+            return WorkStatus.PROBABLY_DONE
+        if current_copyright == release_copyright:
+            return WorkStatus.TODO
+        # Give up
+        return WorkStatus.UNKNOWN
+
+    def status(self):
+        return self.merge_status(), self.work_status()
+
+    @staticmethod
+    def checksum(path):
+        """Returns a checksum string for a file, SHA256 as a hex string."""
+        try:
+            with open(path, 'rb') as file:
+                bytes = file.read()
+                return hashlib.sha256(bytes).hexdigest()
+        except:
+            return None
+
+    @staticmethod
+    def get_copyright(file):
+        """Returns the upstream copyright line for a file."""
+        try:
+            with open(file, 'r') as file:
+                for count in range(5):
+                    line = file.readline()
+                    if line.startswith(
+                            ' * Copyright') and 'Android' not in line:
+                        return line
+                return None
+        except:
+            return None
+
+
+def main():
+    parser = argparse.ArgumentParser(
+            description='Report on merge status of Java packages',
+            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+    # TODO(prb): Add help for available repositories
+    parser.add_argument('-b', '--baseline', default='expected',
+                        help='Baseline repo')
+    parser.add_argument('-r', '--release', default='sc-release',
+                        help='Last released repo')
+    parser.add_argument('-u', '--upstream', default='11+28',
+                        help='Upstream repo.')
+    parser.add_argument('-c', '--current', default='ojluni',
+                        help='Current repo.')
+    parser.add_argument('pkgs', nargs="+",
+                        help='Packages to report on')
+
+    args = parser.parse_args()
+    config = MergeConfig(args.baseline, args.release, args.current,
+                         args.upstream)
+
+    for pkg_name in args.pkgs:
+        try:
+            package = JavaPackage(config, pkg_name)
+            package.report_merge_status()
+        except Exception as e:
+            print(red("ERROR: Unable to process package " + pkg_name + e))
+
+
+if __name__ == "__main__":
+    main()
diff --git a/tools/upstream/src/main/java/libcore/CompareUpstreams.java b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
index d9588a7..c2b6cde 100644
--- a/tools/upstream/src/main/java/libcore/CompareUpstreams.java
+++ b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
@@ -165,6 +165,7 @@
             headers.add(upstream.name());
         }
         headers.add("diff");
+        headers.add("guessed_upstream_path");
         printTsv(out, headers);
 
         Path snapshotRoot = COMPARE_AGAINST_UPSTREAM_SNAPSHOT
@@ -217,6 +218,8 @@
             String changedCommentsSummary = androidChangedCommentsSummary(linesB);
 
             String diffCommand = "";
+            String guessed_upstream_path = guessedUpstream != null ?
+                "" + guessedUpstream.pathFromRepository(relPath) : "";
             if (!comparisons.get(0).equals("identical")) {
                 Path expectedUpstreamPath = expectedUpstream.pathFromRepository(relPath);
                 if (expectedUpstreamPath != null) {
@@ -232,6 +235,7 @@
             values.add(changedCommentsSummary);
             values.addAll(comparisons);
             values.add(diffCommand);
+            values.add(guessed_upstream_path);
             printTsv(out, values);
         }
     }
diff --git a/tools/upstream/src/main/java/libcore/Repository.java b/tools/upstream/src/main/java/libcore/Repository.java
index 4c7bbd7..51a3a69 100644
--- a/tools/upstream/src/main/java/libcore/Repository.java
+++ b/tools/upstream/src/main/java/libcore/Repository.java
@@ -167,6 +167,36 @@
     }
 
     /**
+     * A checkout of the hg repository of OpenJDK 11 or higher, located in the
+     * subdirectory {@code upstreamName} under the directory {@code upstreamRoot}.
+     */
+    public static Repository openJdk11(Path upstreamRoot, String upstreamName) {
+        List<String> sourceDirs = Arrays.asList(
+            "src/java.base/share/classes",
+            "src/java.logging/share/classes",
+            "src/java.prefs/share/classes",
+            "src/java.sql/share/classes",
+            "src/java.desktop/share/classes",
+            "src/java.base/solaris/classes",
+            "src/java.base/unix/classes",
+            "src/java.prefs/unix/classes",
+            "src/jdk.unsupported/share/classes",
+            "src/jdk.net/share/classes",
+            "src/java.base/linux/classes",
+            "build/linux-x86_64-normal-server-release/support/gensrc/java.base",
+
+            // Native (.c) files
+            "src/java.base/unix/native/libjava",
+            "src/java.base/share/native/libjava",
+            "src/java.base/unix/native/libnio",
+            "src/java.base/unix/native/libnio/ch",
+            "src/java.base/unix/native/libnio/fs",
+            "src/java.base/unix/native/libnet"
+        );
+        return new OpenJdkRepository(upstreamRoot, upstreamName, sourceDirs);
+    }
+
+    /**
      * A checkout of the hg repository of OpenJDK 8 or earlier, located in the
      * subdirectory {@code upstreamName} under the directory {@code upstreamRoot}.
      */
diff --git a/tools/upstream/src/main/java/libcore/StandardRepositories.java b/tools/upstream/src/main/java/libcore/StandardRepositories.java
index 7047c60..9b74f55 100644
--- a/tools/upstream/src/main/java/libcore/StandardRepositories.java
+++ b/tools/upstream/src/main/java/libcore/StandardRepositories.java
@@ -28,6 +28,7 @@
 import libcore.Repository.OjluniRepository;
 
 import static libcore.Repository.openJdk9;
+import static libcore.Repository.openJdk11;
 import static libcore.Repository.openJdkLegacy;
 
 public class StandardRepositories {
@@ -51,10 +52,12 @@
         this.openJdk8u222 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "8u222-b01"));
         this.openJdk9p181 = addAndReturn(allUpstreams, openJdk9(upstreamRoot, "9+181"));
         Repository openJdk8u60 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "8u60"));
+        Repository openJdk11p28 = addAndReturn(allUpstreams, openJdk11(upstreamRoot, "11+28"));
         this.openJdk7u40 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "7u40"));
         this.allUpstreams = Collections.unmodifiableList(new ArrayList<>(allUpstreams));
         this.historicUpstreams = Collections.unmodifiableList(new ArrayList<>(
-                Arrays.asList(openJdk8u60, openJdk7u40)
+                Arrays.asList(openJdk8u121, openJdk8u60, openJdk11p28, openJdk9p181, openJdk9b113,
+                    openJdk7u40)
         ));
         this.ojluni = new OjluniRepository(buildTop);
     }