changeset 16974:15cb1241abad

Merge
author lana
date Thu, 13 Apr 2017 16:27:18 +0000
parents 46e1898b6c6e 2a15003cb4b7
children b289db56c862
files
diffstat 45 files changed, 1038 insertions(+), 502 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -42,10 +42,10 @@
  * @author Andreas Sterbenz
  * @since 1.4.2
  */
-final class CounterMode extends FeedbackCipher {
+class CounterMode extends FeedbackCipher {
 
     // current counter value
-    private final byte[] counter;
+    final byte[] counter;
 
     // encrypted bytes of the previous counter value
     private final byte[] encryptedCounter;
--- a/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -29,52 +29,43 @@
 
 package com.sun.crypto.provider;
 
-import java.security.*;
-import javax.crypto.*;
+import javax.crypto.IllegalBlockSizeException;
 import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
 
 /**
  * This class represents the GCTR function defined in NIST 800-38D
- * under section 6.5. It needs to be constructed w/ an initialized
- * cipher object, and initial counter block(ICB). Given an input X
- * of arbitrary length, it processes and returns an output which has
- * the same length as X. The invariants of this class are:
- *
- * (1) The length of intialCounterBlk (and also of its clones, e.g.,
- * fields counter and counterSave) is equal to AES_BLOCK_SIZE.
- *
- * (2) After construction, the field counter never becomes null, it
- * always contains a byte array of length AES_BLOCK_SIZE.
+ * under section 6.5.  With a given cipher object and initial counter
+ * block, a counter mode operation is performed.  Blocksize is limited
+ * to 16 bytes.
  *
  * If any invariant is broken, failures can occur because the
  * AESCrypt.encryptBlock method can be intrinsified on the HotSpot VM
  * (see JDK-8067648 for details).
  *
+ * The counter mode operations can be intrinsified and parallelized
+ * by using CounterMode.implCrypt() if HotSpot VM supports it on the
+ * architecture.
+ *
  * <p>This function is used in the implementation of GCM mode.
  *
  * @since 1.8
  */
-final class GCTR {
+final class GCTR extends CounterMode {
 
-    // these fields should not change after the object has been constructed
-    private final SymmetricCipher aes;
-    private final byte[] icb;
-
-    // the current counter value
-    private byte[] counter;
-
-    // needed for save/restore calls
-    private byte[] counterSave = null;
-
-    // NOTE: cipher should already be initialized
     GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) {
-        this.aes = cipher;
+        super(cipher);
         if (initialCounterBlk.length != AES_BLOCK_SIZE) {
             throw new RuntimeException("length of initial counter block (" + initialCounterBlk.length +
                                        ") not equal to AES_BLOCK_SIZE (" + AES_BLOCK_SIZE + ")");
         }
-        this.icb = initialCounterBlk;
-        this.counter = icb.clone();
+
+        iv = initialCounterBlk;
+        reset();
+    }
+
+    @Override
+    String getFeedback() {
+        return "GCTR";
     }
 
     // input must be multiples of 128-bit blocks when calling update
@@ -89,23 +80,11 @@
             throw new RuntimeException("output buffer too small");
         }
 
-        byte[] encryptedCntr = new byte[AES_BLOCK_SIZE];
-
-        int numOfCompleteBlocks = inLen / AES_BLOCK_SIZE;
-        for (int i = 0; i < numOfCompleteBlocks; i++) {
-            aes.encryptBlock(counter, 0, encryptedCntr, 0);
-            for (int n = 0; n < AES_BLOCK_SIZE; n++) {
-                int index = (i * AES_BLOCK_SIZE + n);
-                out[outOfs + index] =
-                    (byte) ((in[inOfs + index] ^ encryptedCntr[n]));
-            }
-            GaloisCounterMode.increment32(counter);
-        }
-        return inLen;
+        return encrypt(in, inOfs, inLen, out, outOfs);
     }
 
     // input can be arbitrary size when calling doFinal
-    protected int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
+    int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
                           int outOfs) throws IllegalBlockSizeException {
         try {
             if (inLen < 0) {
@@ -118,7 +97,7 @@
                 if (lastBlockSize != 0) {
                     // do the last partial block
                     byte[] encryptedCntr = new byte[AES_BLOCK_SIZE];
-                    aes.encryptBlock(counter, 0, encryptedCntr, 0);
+                    embeddedCipher.encryptBlock(counter, 0, encryptedCntr, 0);
                     for (int n = 0; n < lastBlockSize; n++) {
                         out[outOfs + completeBlkLen + n] =
                             (byte) ((in[inOfs + completeBlkLen + n] ^
@@ -131,28 +110,4 @@
         }
         return inLen;
     }
-
-    /**
-     * Resets the content of this object to when it's first constructed.
-     */
-    void reset() {
-        System.arraycopy(icb, 0, counter, 0, icb.length);
-        counterSave = null;
-    }
-
-    /**
-     * Save the current content of this object.
-     */
-    void save() {
-        this.counterSave = this.counter.clone();
-    }
-
-    /**
-     * Restores the content of this object to the previous saved one.
-     */
-    void restore() {
-        if (this.counterSave != null) {
-            this.counter = this.counterSave;
-        }
-    }
 }
--- a/src/java.base/share/classes/java/io/FilePermission.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/io/FilePermission.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -209,6 +209,10 @@
     private static final Path here = builtInFS.getPath(
             GetPropertyAction.privilegedGetProperty("user.dir"));
 
+    private static final Path EMPTY_PATH = builtInFS.getPath("");
+    private static final Path DASH_PATH = builtInFS.getPath("-");
+    private static final Path DOTDOT_PATH = builtInFS.getPath("..");
+
     /**
      * A private constructor that clones some and updates some,
      * always with a different name.
@@ -341,7 +345,7 @@
                         .normalize();
                 // lastName should always be non-null now
                 Path lastName = npath.getFileName();
-                if (lastName != null && lastName.toString().equals("-")) {
+                if (lastName != null && lastName.equals(DASH_PATH)) {
                     directory = true;
                     recursive = !rememberStar;
                     npath = npath.getParent();
@@ -679,23 +683,76 @@
      * @return the depth in between
      */
     private static int containsPath(Path p1, Path p2) {
-        Path p;
-        try {
-            p = p2.relativize(p1).normalize();
-            if (p.getName(0).toString().isEmpty()) {
-                return 0;
-            } else {
-                for (Path item: p) {
-                    String s = item.toString();
-                    if (!s.equals("..")) {
-                        return -1;
-                    }
-                }
-                return p.getNameCount();
-            }
-        } catch (IllegalArgumentException iae) {
+
+        // Two paths must have the same root. For example,
+        // there is no contains relation between any two of
+        // "/x", "x", "C:/x", "C:x", and "//host/share/x".
+        if (!Objects.equals(p1.getRoot(), p2.getRoot())) {
             return -1;
         }
+
+        // Empty path (i.e. "." or "") is a strange beast,
+        // because its getNameCount()==1 but getName(0) is null.
+        // It's better to deal with it separately.
+        if (p1.equals(EMPTY_PATH)) {
+            if (p2.equals(EMPTY_PATH)) {
+                return 0;
+            } else if (p2.getName(0).equals(DOTDOT_PATH)) {
+                // "." contains p2 iif p2 has no "..". Since a
+                // a normalized path can only have 0 or more
+                // ".." at the beginning. We only need to look
+                // at the head.
+                return -1;
+            } else {
+                // and the distance is p2's name count. i.e.
+                // 3 between "." and "a/b/c".
+                return p2.getNameCount();
+            }
+        } else if (p2.equals(EMPTY_PATH)) {
+            int c1 = p1.getNameCount();
+            if (!p1.getName(c1 - 1).equals(DOTDOT_PATH)) {
+                // "." is inside p1 iif p1 is 1 or more "..".
+                // For the same reason above, we only need to
+                // look at the tail.
+                return -1;
+            }
+            // and the distance is the count of ".."
+            return c1;
+        }
+
+        // Good. No more empty paths.
+
+        // Common heads are removed
+
+        int c1 = p1.getNameCount();
+        int c2 = p2.getNameCount();
+
+        int n = Math.min(c1, c2);
+        int i = 0;
+        while (i < n) {
+            if (!p1.getName(i).equals(p2.getName(i)))
+                break;
+            i++;
+        }
+
+        // for p1 containing p2, p1 must be 0-or-more "..",
+        // and p2 cannot have "..". For the same reason, we only
+        // check tail of p1 and head of p2.
+        if (i < c1 && !p1.getName(c1 - 1).equals(DOTDOT_PATH)) {
+            return -1;
+        }
+
+        if (i < c2 && p2.getName(i).equals(DOTDOT_PATH)) {
+            return -1;
+        }
+
+        // and the distance is the name counts added (after removing
+        // the common heads).
+
+        // For example: p1 = "../../..", p2 = "../a".
+        // After removing the common heads, they become "../.." and "a",
+        // and the distance is (3-1)+(2-1) = 3.
+        return c1 - i + c2 - i;
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -307,6 +307,8 @@
      *             sequence.
      */
     public int codePointAt(int index) {
+        int count = this.count;
+        byte[] value = this.value;
         checkIndex(index, count);
         if (isLatin1()) {
             return value[index] & 0xff;
@@ -560,11 +562,7 @@
             val[count++] = 'l';
             val[count++] = 'l';
         } else {
-            checkOffset(count + 4, val.length >> 1);
-            StringUTF16.putChar(val, count++, 'n');
-            StringUTF16.putChar(val, count++, 'u');
-            StringUTF16.putChar(val, count++, 'l');
-            StringUTF16.putChar(val, count++, 'l');
+            count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
         }
         this.count = count;
         return this;
@@ -695,18 +693,9 @@
             }
         } else {
             if (b) {
-                checkOffset(count + 4, val.length >> 1);
-                StringUTF16.putChar(val, count++, 't');
-                StringUTF16.putChar(val, count++, 'r');
-                StringUTF16.putChar(val, count++, 'u');
-                StringUTF16.putChar(val, count++, 'e');
+                count = StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e');
             } else {
-                checkOffset(count + 5, val.length >> 1);
-                StringUTF16.putChar(val, count++, 'f');
-                StringUTF16.putChar(val, count++, 'a');
-                StringUTF16.putChar(val, count++, 'l');
-                StringUTF16.putChar(val, count++, 's');
-                StringUTF16.putChar(val, count++, 'e');
+                count = StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
             }
         }
         this.count = count;
@@ -755,16 +744,15 @@
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(int i) {
+        int count = this.count;
         int spaceNeeded = count + Integer.stringSize(i);
         ensureCapacityInternal(spaceNeeded);
         if (isLatin1()) {
             Integer.getChars(i, spaceNeeded, value);
         } else {
-            byte[] val = this.value;
-            checkOffset(spaceNeeded, val.length >> 1);
-            Integer.getCharsUTF16(i, spaceNeeded, val);
+            StringUTF16.getChars(i, count, spaceNeeded, value);
         }
-        count = spaceNeeded;
+        this.count = spaceNeeded;
         return this;
     }
 
@@ -781,16 +769,15 @@
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(long l) {
+        int count = this.count;
         int spaceNeeded = count + Long.stringSize(l);
         ensureCapacityInternal(spaceNeeded);
         if (isLatin1()) {
             Long.getChars(l, spaceNeeded, value);
         } else {
-            byte[] val = this.value;
-            checkOffset(spaceNeeded, val.length >> 1);
-            Long.getCharsUTF16(l, spaceNeeded, val);
+            StringUTF16.getChars(l, count, spaceNeeded, value);
         }
-        count = spaceNeeded;
+        this.count = spaceNeeded;
         return this;
     }
 
@@ -843,6 +830,7 @@
      *             greater than {@code end}.
      */
     public AbstractStringBuilder delete(int start, int end) {
+        int count = this.count;
         if (end > count) {
             end = count;
         }
@@ -850,7 +838,7 @@
         int len = end - start;
         if (len > 0) {
             shift(end, -len);
-            count -= len;
+            this.count = count - len;
         }
         return this;
     }
@@ -925,6 +913,7 @@
      *             greater than {@code end}.
      */
     public AbstractStringBuilder replace(int start, int end, String str) {
+        int count = this.count;
         if (end > count) {
             end = count;
         }
@@ -933,7 +922,7 @@
         int newCount = count + len - (end - start);
         ensureCapacityInternal(newCount);
         shift(end, newCount - count);
-        count = newCount;
+        this.count = newCount;
         putStringAt(start, str);
         return this;
     }
@@ -1500,40 +1489,11 @@
                 val[k] = cj;
             }
         } else {
-            checkOffset(count, val.length >> 1);
-            boolean hasSurrogates = false;
-            for (int j = (n-1) >> 1; j >= 0; j--) {
-                int k = n - j;
-                char cj = StringUTF16.getChar(val, j);
-                char ck = StringUTF16.getChar(val, k);
-                StringUTF16.putChar(val, j, ck);
-                StringUTF16.putChar(val, k, cj);
-                if (Character.isSurrogate(cj) ||
-                    Character.isSurrogate(ck)) {
-                    hasSurrogates = true;
-                }
-            }
-            if (hasSurrogates) {
-                reverseAllValidSurrogatePairs(val, count);
-            }
+            StringUTF16.reverse(val, count);
         }
         return this;
     }
 
-    /** Outlined helper method for reverse() */
-    private void reverseAllValidSurrogatePairs(byte[] val, int count) {
-        for (int i = 0; i < count - 1; i++) {
-            char c2 = StringUTF16.getChar(val, i);
-            if (Character.isLowSurrogate(c2)) {
-                char c1 = StringUTF16.getChar(val, i + 1);
-                if (Character.isHighSurrogate(c1)) {
-                    StringUTF16.putChar(val, i++, c1);
-                    StringUTF16.putChar(val, i, c2);
-                }
-            }
-        }
-    }
-
     /**
      * Returns a string representing the data in this sequence.
      * A new {@code String} object is allocated and initialized to
@@ -1682,6 +1642,7 @@
     }
 
     private final void appendChars(char[] s, int off, int end) {
+        int count = this.count;
         if (isLatin1()) {
             byte[] val = this.value;
             for (int i = off, j = count; i < end; i++) {
@@ -1689,17 +1650,17 @@
                 if (StringLatin1.canEncode(c)) {
                     val[j++] = (byte)c;
                 } else {
-                    count = j;
+                    this.count = count = j;
                     inflate();
                     StringUTF16.putCharsSB(this.value, j, s, i, end);
-                    count += end - i;
+                    this.count = count + end - i;
                     return;
                 }
             }
         } else {
             StringUTF16.putCharsSB(this.value, count, s, off, end);
         }
-        count += end - off;
+        this.count = count + end - off;
     }
 
     private final void appendChars(CharSequence s, int off, int end) {
--- a/src/java.base/share/classes/java/lang/Integer.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/Integer.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -386,7 +386,7 @@
     }
 
     /** byte[]/UTF16 version    */
-    static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {
+    private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {
         int charPos = offset + len;
         int radix = 1 << shift;
         int mask = radix - 1;
@@ -442,7 +442,7 @@
             return new String(buf, LATIN1);
         } else {
             byte[] buf = new byte[size * 2];
-            getCharsUTF16(i, size, buf);
+            StringUTF16.getChars(i, size, buf);
             return new String(buf, UTF16);
         }
     }
@@ -516,49 +516,6 @@
         return charPos;
     }
 
-    /**
-     * This is a variant of {@link #getChars(int, int, byte[])}, but for
-     * UTF-16 coder.
-     *
-     * @param i     value to convert
-     * @param index next index, after the least significant digit
-     * @param buf   target buffer, UTF16-coded.
-     * @return index of the most significant digit or minus sign, if present
-     */
-    static int getCharsUTF16(int i, int index, byte[] buf) {
-        int q, r;
-        int charPos = index;
-
-        boolean negative = (i < 0);
-        if (!negative) {
-            i = -i;
-        }
-
-        // Get 2 digits/iteration using ints
-        while (i <= -100) {
-            q = i / 100;
-            r = (q * 100) - i;
-            i = q;
-            StringUTF16.putChar(buf, --charPos, DigitOnes[r]);
-            StringUTF16.putChar(buf, --charPos, DigitTens[r]);
-        }
-
-        // We know there are at most two digits left at this point.
-        q = i / 10;
-        r = (q * 10) - i;
-        StringUTF16.putChar(buf, --charPos, '0' + r);
-
-        // Whatever left is the remaining digit.
-        if (q < 0) {
-            StringUTF16.putChar(buf, --charPos, '0' - q);
-        }
-
-        if (negative) {
-            StringUTF16.putChar(buf, --charPos, '-');
-        }
-        return charPos;
-    }
-
     // Left here for compatibility reasons, see JDK-8143900.
     static final int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                       99999999, 999999999, Integer.MAX_VALUE };
--- a/src/java.base/share/classes/java/lang/Long.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/Long.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -414,7 +414,7 @@
     }
 
     /** byte[]/UTF16 version    */
-    static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) {
+    private static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) {
         int charPos = offset + len;
         int radix = 1 << shift;
         int mask = radix - 1;
@@ -475,7 +475,7 @@
             return new String(buf, LATIN1);
         } else {
             byte[] buf = new byte[size * 2];
-            getCharsUTF16(i, size, buf);
+            StringUTF16.getChars(i, size, buf);
             return new String(buf, UTF16);
         }
     }
@@ -562,61 +562,6 @@
     }
 
     /**
-     * This is a variant of {@link #getChars(long, int, byte[])}, but for
-     * UTF-16 coder.
-     *
-     * @param i     value to convert
-     * @param index next index, after the least significant digit
-     * @param buf   target buffer, UTF16-coded.
-     * @return index of the most significant digit or minus sign, if present
-     */
-    static int getCharsUTF16(long i, int index, byte[] buf) {
-        long q;
-        int r;
-        int charPos = index;
-
-        boolean negative = (i < 0);
-        if (!negative) {
-            i = -i;
-        }
-
-        // Get 2 digits/iteration using longs until quotient fits into an int
-        while (i <= Integer.MIN_VALUE) {
-            q = i / 100;
-            r = (int)((q * 100) - i);
-            i = q;
-            StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
-            StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
-        }
-
-        // Get 2 digits/iteration using ints
-        int q2;
-        int i2 = (int)i;
-        while (i2 <= -100) {
-            q2 = i2 / 100;
-            r  = (q2 * 100) - i2;
-            i2 = q2;
-            StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
-            StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
-        }
-
-        // We know there are at most two digits left at this point.
-        q2 = i2 / 10;
-        r  = (q2 * 10) - i2;
-        StringUTF16.putChar(buf, --charPos, '0' + r);
-
-        // Whatever left is the remaining digit.
-        if (q2 < 0) {
-            StringUTF16.putChar(buf, --charPos, '0' - q2);
-        }
-
-        if (negative) {
-            StringUTF16.putChar(buf, --charPos, '-');
-        }
-        return charPos;
-    }
-
-    /**
      * Returns the string representation size for a given long value.
      *
      * @param x long value
--- a/src/java.base/share/classes/java/lang/Process.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/Process.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,10 +80,10 @@
  *
  * <p>Subclasses of Process should override the {@link #onExit()} and
  * {@link #toHandle()} methods to provide a fully functional Process including the
- * {@link #getPid() process id},
- * {@link #info() information about the process},
- * {@link #children() direct children}, and
- * {@link #descendants() direct children plus descendants of those children} of the process.
+ * {@linkplain #pid() process id},
+ * {@linkplain #info() information about the process},
+ * {@linkplain #children() direct children}, and
+ * {@linkplain #descendants() direct children plus descendants of those children} of the process.
  * Delegating to the underlying Process or ProcessHandle is typically
  * easiest and most efficient.
  *
@@ -237,14 +237,14 @@
     /**
      * Kills the process.
      * Whether the process represented by this {@code Process} object is
-     * {@link #supportsNormalTermination normally terminated} or not is
+     * {@linkplain #supportsNormalTermination normally terminated} or not is
      * implementation dependent.
      * Forcible process destruction is defined as the immediate termination of a
      * process, whereas normal termination allows the process to shut down cleanly.
      * If the process is not alive, no action is taken.
      * <p>
      * The {@link java.util.concurrent.CompletableFuture} from {@link #onExit} is
-     * {@link java.util.concurrent.CompletableFuture#complete completed}
+     * {@linkplain java.util.concurrent.CompletableFuture#complete completed}
      * when the process has terminated.
      */
     public abstract void destroy();
@@ -257,7 +257,7 @@
      * If the process is not alive, no action is taken.
      * <p>
      * The {@link java.util.concurrent.CompletableFuture} from {@link #onExit} is
-     * {@link java.util.concurrent.CompletableFuture#complete completed}
+     * {@linkplain java.util.concurrent.CompletableFuture#complete completed}
      * when the process has terminated.
      * <p>
      * Invoking this method on {@code Process} objects returned by
@@ -335,15 +335,15 @@
      *
      * @implSpec
      * The implementation of this method returns the process id as:
-     * {@link #toHandle toHandle().getPid()}.
+     * {@link #toHandle toHandle().pid()}.
      *
      * @return the native process id of the process
      * @throws UnsupportedOperationException if the Process implementation
      *         does not support this operation
      * @since 9
      */
-    public long getPid() {
-        return toHandle().getPid();
+    public long pid() {
+        return toHandle().pid();
     }
 
     /**
@@ -357,9 +357,9 @@
      * <p>
      * Calling {@code onExit().get()} waits for the process to terminate and returns
      * the Process. The future can be used to check if the process is
-     * {@link java.util.concurrent.CompletableFuture#isDone done} or to
-     * {@link java.util.concurrent.CompletableFuture#get() wait} for it to terminate.
-     * {@link java.util.concurrent.CompletableFuture#cancel(boolean) Cancelling}
+     * {@linkplain java.util.concurrent.CompletableFuture#isDone done} or to
+     * {@linkplain java.util.concurrent.CompletableFuture#get() wait} for it to terminate.
+     * {@linkplain java.util.concurrent.CompletableFuture#cancel(boolean) Cancelling}
      * the CompletableFuture does not affect the Process.
      * <p>
      * Processes returned from {@link ProcessBuilder#start} override the
@@ -389,7 +389,7 @@
      * {@code waitFor} is interrupted, the thread's interrupt status is preserved.
      * <p>
      * When {@link #waitFor()} returns successfully the CompletableFuture is
-     * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
+     * {@linkplain java.util.concurrent.CompletableFuture#complete completed} regardless
      * of the exit status of the process.
      *
      * This implementation may consume a lot of memory for thread stacks if a
@@ -463,7 +463,7 @@
      * This implementation throws an instance of
      * {@link java.lang.UnsupportedOperationException} and performs no other action.
      * Subclasses should override this method to provide a ProcessHandle for the
-     * process.  The methods {@link #getPid}, {@link #info}, {@link #children},
+     * process.  The methods {@link #pid}, {@link #info}, {@link #children},
      * and {@link #descendants}, unless overridden, operate on the ProcessHandle.
      *
      * @return Returns a ProcessHandle for the Process
@@ -500,10 +500,10 @@
     /**
      * Returns a snapshot of the direct children of the process.
      * The parent of a direct child process is the process.
-     * Typically, a process that is {@link #isAlive not alive} has no children.
+     * Typically, a process that is {@linkplain #isAlive not alive} has no children.
      * <p>
      * <em>Note that processes are created and terminate asynchronously.
-     * There is no guarantee that a process is {@link #isAlive alive}.
+     * There is no guarantee that a process is {@linkplain #isAlive alive}.
      * </em>
      *
      * @implSpec
@@ -526,10 +526,10 @@
      * Returns a snapshot of the descendants of the process.
      * The descendants of a process are the children of the process
      * plus the descendants of those children, recursively.
-     * Typically, a process that is {@link #isAlive not alive} has no children.
+     * Typically, a process that is {@linkplain #isAlive not alive} has no children.
      * <p>
      * <em>Note that processes are created and terminate asynchronously.
-     * There is no guarantee that a process is {@link #isAlive alive}.
+     * There is no guarantee that a process is {@linkplain #isAlive alive}.
      * </em>
      *
      * @implSpec
--- a/src/java.base/share/classes/java/lang/ProcessHandle.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/ProcessHandle.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -104,7 +104,7 @@
      * @throws UnsupportedOperationException if the implementation
      *         does not support this operation
      */
-    long getPid();
+    long pid();
 
     /**
      * Returns an {@code Optional<ProcessHandle>} for an existing native process.
@@ -383,7 +383,7 @@
     /**
      * Returns a hash code value for this ProcessHandle.
      * The hashcode value follows the general contract for {@link Object#hashCode()}.
-     * The value is a function of the {@link #getPid getPid()} value and
+     * The value is a function of the {@link #pid pid()} value and
      * may be a function of additional information to uniquely identify the process.
      * If two ProcessHandles are equal according to the {@link #equals(Object) equals}
      * method, then calling the hashCode method on each of the two objects
--- a/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Thu Apr 13 16:27:18 2017 +0000
@@ -35,11 +35,7 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
-import java.util.concurrent.ForkJoinPool;
-import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
@@ -176,7 +172,7 @@
             throw new IllegalStateException("onExit for current process not allowed");
         }
 
-        return ProcessHandleImpl.completion(getPid(), false)
+        return ProcessHandleImpl.completion(pid(), false)
                 .handleAsync((exitStatus, unusedThrowable) -> this);
     }
 
@@ -259,7 +255,7 @@
      * @return the native process ID
      */
     @Override
-    public long getPid() {
+    public long pid() {
         return pid;
     }
 
--- a/src/java.base/share/classes/java/lang/String.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/String.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -1064,11 +1064,7 @@
             if (!isLatin1()) {  // utf16 str and latin1 abs can never be "equal"
                 return false;
             }
-            for (int i = 0; i < len; i++) {
-                if ((char)(v1[i] & 0xff) != StringUTF16.getChar(v2, i)) {
-                    return false;
-                }
-            }
+            return StringUTF16.contentEquals(v1, v2, len);
         }
         return true;
     }
@@ -1120,10 +1116,8 @@
                 }
             }
         } else {
-            for (int i = 0; i < n; i++) {
-                if (StringUTF16.getChar(val, i) != cs.charAt(i)) {
-                    return false;
-                }
+            if (!StringUTF16.contentEquals(val, cs, n)) {
+                return false;
             }
         }
         return true;
@@ -1734,6 +1728,9 @@
         if (tgtCount == 0) {
             return fromIndex;
         }
+        if (tgtCount > srcCount) {
+            return -1;
+        }
         if (srcCoder == tgtCoder) {
             return srcCoder == LATIN1
                 ? StringLatin1.indexOf(src, srcCount, tgt, tgtCount, fromIndex)
@@ -1792,7 +1789,7 @@
      * is the string being searched for.
      *
      * @param   src         the characters being searched.
-     * @param   srcCoder  coder handles the mapping between bytes/chars
+     * @param   srcCoder    coder handles the mapping between bytes/chars
      * @param   srcCount    count of the source string.
      * @param   tgt         the characters being searched for.
      * @param   fromIndex   the index to begin searching from.
@@ -1807,12 +1804,12 @@
          * consistency, don't check for null str.
          */
         int rightIndex = srcCount - tgtCount;
+        if (fromIndex > rightIndex) {
+            fromIndex = rightIndex;
+        }
         if (fromIndex < 0) {
             return -1;
         }
-        if (fromIndex > rightIndex) {
-            fromIndex = rightIndex;
-        }
         /* Empty string always matches. */
         if (tgtCount == 0) {
             return fromIndex;
@@ -1825,31 +1822,8 @@
         if (srcCoder == LATIN1) {    // && tgtCoder == UTF16
             return -1;
         }
-                                     // srcCoder == UTF16 && tgtCoder == LATIN1
-        int min = tgtCount - 1;
-        int i = min + fromIndex;
-        int strLastIndex = tgtCount - 1;
-
-        char strLastChar = (char)(tgt[strLastIndex] & 0xff);
-    startSearchForLastChar:
-        while (true) {
-            while (i >= min && StringUTF16.getChar(src, i) != strLastChar) {
-                i--;
-            }
-            if (i < min) {
-                return -1;
-            }
-            int j = i - 1;
-            int start = j - strLastIndex;
-            int k = strLastIndex - 1;
-            while (j > start) {
-                if (StringUTF16.getChar(src, j--) != (tgt[k--] & 0xff)) {
-                    i--;
-                    continue startSearchForLastChar;
-                }
-            }
-            return start + 1;
-        }
+        // srcCoder == UTF16 && tgtCoder == LATIN1
+        return StringUTF16.lastIndexOfLatin1(src, srcCount, tgt, tgtCount, fromIndex);
     }
 
     /**
@@ -3078,7 +3052,8 @@
      */
     static void checkIndex(int index, int length) {
         if (index < 0 || index >= length) {
-            throw new StringIndexOutOfBoundsException("index " + index);
+            throw new StringIndexOutOfBoundsException("index " + index +
+                                                      ",length " + length);
         }
     }
 
@@ -3116,7 +3091,7 @@
      *          If {@code begin} is negative, {@code begin} is greater than
      *          {@code end}, or {@code end} is greater than {@code length}.
      */
-    private static void checkBoundsBeginEnd(int begin, int end, int length) {
+    static void checkBoundsBeginEnd(int begin, int end, int length) {
         if (begin < 0 || begin > end || end > length) {
             throw new StringIndexOutOfBoundsException(
                 "begin " + begin + ", end " + end + ", length " + length);
--- a/src/java.base/share/classes/java/lang/StringConcatHelper.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -293,7 +293,7 @@
         if (coder == String.LATIN1) {
             return Integer.getChars(value, index, buf);
         } else {
-            return Integer.getCharsUTF16(value, index, buf);
+            return StringUTF16.getChars(value, index, buf);
         }
     }
 
@@ -311,7 +311,7 @@
         if (coder == String.LATIN1) {
             return Long.getChars(value, index, buf);
         } else {
-            return Long.getCharsUTF16(value, index, buf);
+            return StringUTF16.getChars(value, index, buf);
         }
     }
 
--- a/src/java.base/share/classes/java/lang/StringLatin1.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/StringLatin1.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -36,7 +36,6 @@
 import static java.lang.String.LATIN1;
 import static java.lang.String.UTF16;
 import static java.lang.String.checkOffset;
-import static java.lang.String.checkBoundsOffCount;
 
 final class StringLatin1 {
 
@@ -566,11 +565,7 @@
     // inflatedCopy byte[] -> byte[]
     @HotSpotIntrinsicCandidate
     public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
-        // We need a range check here because 'putChar' has no checks
-        checkBoundsOffCount(dstOff << 1, len << 1, dst.length);
-        for (int i = 0; i < len; i++) {
-            StringUTF16.putChar(dst, dstOff++, src[srcOff++] & 0xff);
-        }
+        StringUTF16.inflate(src, srcOff, dst, dstOff, len);
     }
 
     static class CharsSpliterator implements Spliterator.OfInt {
--- a/src/java.base/share/classes/java/lang/StringUTF16.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -30,12 +30,11 @@
 import java.util.Spliterator;
 import java.util.function.IntConsumer;
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.vm.annotation.ForceInline;
+import jdk.internal.vm.annotation.DontInline;
 
 import static java.lang.String.UTF16;
 import static java.lang.String.LATIN1;
-import static java.lang.String.checkIndex;
-import static java.lang.String.checkOffset;
-import static java.lang.String.checkBoundsOffCount;
 
 final class StringUTF16 {
 
@@ -51,33 +50,37 @@
     }
 
     @HotSpotIntrinsicCandidate
-    public static void putChar(byte[] val, int index, int c) {
+    // intrinsic performs no bounds checks
+    static void putChar(byte[] val, int index, int c) {
+        assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
         index <<= 1;
         val[index++] = (byte)(c >> HI_BYTE_SHIFT);
         val[index]   = (byte)(c >> LO_BYTE_SHIFT);
     }
 
     @HotSpotIntrinsicCandidate
-    public static char getChar(byte[] val, int index) {
+    // intrinsic performs no bounds checks
+    static char getChar(byte[] val, int index) {
+        assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
         index <<= 1;
         return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
                       ((val[index]   & 0xff) << LO_BYTE_SHIFT));
     }
 
-    public static char charAt(byte[] value, int index) {
-        if (index < 0 || index >= value.length >> 1) {
-            throw new StringIndexOutOfBoundsException(index);
-        }
-        return getChar(value, index);
-    }
-
     public static int length(byte[] value) {
         return value.length >> 1;
     }
 
-    public static int codePointAt(byte[] value, int index, int end) {
+    private static int codePointAt(byte[] value, int index, int end, boolean checked) {
+        assert index < end;
+        if (checked) {
+            checkIndex(index, value);
+        }
         char c1 = getChar(value, index);
         if (Character.isHighSurrogate(c1) && ++index < end) {
+            if (checked) {
+                checkIndex(index, value);
+            }
             char c2 = getChar(value, index);
             if (Character.isLowSurrogate(c2)) {
                return Character.toCodePoint(c1, c2);
@@ -86,10 +89,22 @@
         return c1;
     }
 
-    public static int codePointBefore(byte[] value, int index) {
-        char c2 = getChar(value, --index);
+    public static int codePointAt(byte[] value, int index, int end) {
+       return codePointAt(value, index, end, false /* unchecked */);
+    }
+
+    private static int codePointBefore(byte[] value, int index, boolean checked) {
+        --index;
+        if (checked) {
+            checkIndex(index, value);
+        }
+        char c2 = getChar(value, index);
         if (Character.isLowSurrogate(c2) && index > 0) {
-            char c1 = getChar(value, --index);
+            --index;
+            if (checked) {
+                checkIndex(index, value);
+            }
+            char c1 = getChar(value, index);
             if (Character.isHighSurrogate(c1)) {
                return Character.toCodePoint(c1, c2);
             }
@@ -97,11 +112,19 @@
         return c2;
     }
 
-    public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
+    public static int codePointBefore(byte[] value, int index) {
+        return codePointBefore(value, index, false /* unchecked */);
+    }
+
+    private static int codePointCount(byte[] value, int beginIndex, int endIndex, boolean checked) {
+        assert beginIndex <= endIndex;
         int count = endIndex - beginIndex;
-        for (int i = beginIndex; i < endIndex; ) {
+        int i = beginIndex;
+        if (checked && i < endIndex) {
+            checkBoundsBeginEnd(i, endIndex, value);
+        }
+        for (; i < endIndex - 1; ) {
             if (Character.isHighSurrogate(getChar(value, i++)) &&
-                i < endIndex &&
                 Character.isLowSurrogate(getChar(value, i))) {
                 count--;
                 i++;
@@ -110,6 +133,10 @@
         return count;
     }
 
+    public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
+        return codePointCount(value, beginIndex, endIndex, false /* unchecked */);
+    }
+
     public static char[] toChars(byte[] value) {
         char[] dst = new char[value.length >> 1];
         getChars(value, 0, dst.length, dst, 0);
@@ -162,7 +189,7 @@
     @HotSpotIntrinsicCandidate
     public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
         // We need a range check here because 'getChar' has no checks
-        checkBoundsOffCount(srcOff << 1, len << 1, src.length);
+        checkBoundsOffCount(srcOff, len, src);
         for (int i = 0; i < len; i++) {
             char c = getChar(src, srcOff);
             if (c > 0xFF) {
@@ -212,7 +239,7 @@
     public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
         // We need a range check here because 'getChar' has no checks
         if (srcBegin < srcEnd) {
-            checkBoundsOffCount(srcBegin << 1, (srcEnd - srcBegin) << 1, value.length);
+            checkBoundsOffCount(srcBegin, srcEnd - srcBegin, value);
         }
         for (int i = srcBegin; i < srcEnd; i++) {
             dst[dstBegin++] = getChar(value, i);
@@ -319,14 +346,25 @@
         if (str.length == 0) {
             return 0;
         }
-        if (value.length == 0) {
+        if (value.length < str.length) {
             return -1;
         }
-        return indexOf(value, length(value), str, length(str), 0);
+        return indexOfUnsafe(value, length(value), str, length(str), 0);
     }
 
     @HotSpotIntrinsicCandidate
     public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
+        checkBoundsBeginEnd(fromIndex, valueCount, value);
+        checkBoundsBeginEnd(0, strCount, str);
+        return indexOfUnsafe(value, valueCount, str, strCount, fromIndex);
+    }
+
+
+    private static int indexOfUnsafe(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
+        assert fromIndex >= 0;
+        assert strCount > 0;
+        assert strCount <= length(str);
+        assert valueCount >= strCount;
         char first = getChar(str, 0);
         int max = (valueCount - strCount);
         for (int i = fromIndex; i <= max; i++) {
@@ -348,6 +386,7 @@
         return -1;
     }
 
+
     /**
      * Handles indexOf Latin1 substring in UTF16 string.
      */
@@ -356,14 +395,24 @@
         if (str.length == 0) {
             return 0;
         }
-        if (value.length == 0) {
+        if (length(value) < str.length) {
             return -1;
         }
-        return indexOfLatin1(value, length(value), str, str.length, 0);
+        return indexOfLatin1Unsafe(value, length(value), str, str.length, 0);
     }
 
     @HotSpotIntrinsicCandidate
     public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
+        checkBoundsBeginEnd(fromIndex, srcCount, src);
+        String.checkBoundsBeginEnd(0, tgtCount, tgt.length);
+        return indexOfLatin1Unsafe(src, srcCount, tgt, tgtCount, fromIndex);
+    }
+
+    public static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
+        assert fromIndex >= 0;
+        assert tgtCount > 0;
+        assert tgtCount <= tgt.length;
+        assert srcCount >= tgtCount;
         char first = (char)(tgt[0] & 0xff);
         int max = (srcCount - tgtCount);
         for (int i = fromIndex; i <= max; i++) {
@@ -389,6 +438,11 @@
 
     @HotSpotIntrinsicCandidate
     private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) {
+        checkBoundsBeginEnd(fromIndex, max, value);
+        return indexOfCharUnsafe(value, ch, fromIndex, max);
+    }
+
+    private static int indexOfCharUnsafe(byte[] value, int ch, int fromIndex, int max) {
         for (int i = fromIndex; i < max; i++) {
             if (getChar(value, i) == ch) {
                 return i;
@@ -404,6 +458,7 @@
         if (Character.isValidCodePoint(ch)) {
             final char hi = Character.highSurrogate(ch);
             final char lo = Character.lowSurrogate(ch);
+            checkBoundsBeginEnd(fromIndex, max, value);
             for (int i = fromIndex; i < max - 1; i++) {
                 if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) {
                     return i;
@@ -413,13 +468,21 @@
         return -1;
     }
 
+    // srcCoder == UTF16 && tgtCoder == UTF16
     public static int lastIndexOf(byte[] src, int srcCount,
                                   byte[] tgt, int tgtCount, int fromIndex) {
+        assert fromIndex >= 0;
+        assert tgtCount > 0;
+        assert tgtCount <= length(tgt);
         int min = tgtCount - 1;
         int i = min + fromIndex;
         int strLastIndex = tgtCount - 1;
+
+        checkIndex(strLastIndex, tgt);
         char strLastChar = getChar(tgt, strLastIndex);
 
+        checkIndex(i, src);
+
     startSearchForLastChar:
         while (true) {
             while (i >= min && getChar(src, i) != strLastChar) {
@@ -509,6 +572,9 @@
     public static boolean regionMatchesCI(byte[] value, int toffset,
                                           byte[] other, int ooffset, int len) {
         int last = toffset + len;
+        assert toffset >= 0 && ooffset >= 0;
+        assert ooffset + len <= length(other);
+        assert last <= length(value);
         while (toffset < last) {
             char c1 = getChar(value, toffset++);
             char c2 = getChar(other, ooffset++);
@@ -599,6 +665,8 @@
     private static String toLowerCaseEx(String str, byte[] value,
                                         byte[] result, int first, Locale locale,
                                         boolean localeDependent) {
+        assert(result.length == value.length);
+        assert(first >= 0);
         int resultOffset = first;
         int length = value.length >> 1;
         int srcCount;
@@ -633,6 +701,8 @@
                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
                     result = result2;
                 }
+                assert resultOffset >= 0;
+                assert resultOffset + mapLen <= length(result);
                 for (int x = 0; x < mapLen; ++x) {
                     putChar(result, resultOffset++, lowerCharArray[x]);
                 }
@@ -697,6 +767,8 @@
                                         byte[] result, int first,
                                         Locale locale, boolean localeDependent)
     {
+        assert(result.length == value.length);
+        assert(first >= 0);
         int resultOffset = first;
         int length = value.length >> 1;
         int srcCount;
@@ -733,10 +805,12 @@
                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
                     result = result2;
-                 }
-                 for (int x = 0; x < mapLen; ++x) {
+                }
+                assert resultOffset >= 0;
+                assert resultOffset + mapLen <= length(result);
+                for (int x = 0; x < mapLen; ++x) {
                     putChar(result, resultOffset++, upperCharArray[x]);
-                 }
+                }
             }
         }
         return newString(result, 0, resultOffset);
@@ -757,7 +831,7 @@
             null;
     }
 
-    public static void putChars(byte[] val, int index, char[] str, int off, int end) {
+    private static void putChars(byte[] val, int index, char[] str, int off, int end) {
         while (off < end) {
             putChar(val, index++, str[off++]);
         }
@@ -927,35 +1001,172 @@
     ////////////////////////////////////////////////////////////////
 
     public static void putCharSB(byte[] val, int index, int c) {
-        checkIndex(index, val.length >> 1);
+        checkIndex(index, val);
         putChar(val, index, c);
     }
 
     public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
-        checkOffset(index + end - off, val.length >> 1);
+        checkBoundsBeginEnd(index, index + end - off, val);
         putChars(val, index, ca, off, end);
     }
 
     public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
-        checkOffset(index + end - off, val.length >> 1);
+        checkBoundsBeginEnd(index, index + end - off, val);
         for (int i = off; i < end; i++) {
             putChar(val, index++, s.charAt(i));
         }
     }
 
     public static int codePointAtSB(byte[] val, int index, int end) {
-        checkOffset(end, val.length >> 1);
-        return codePointAt(val, index, end);
+        return codePointAt(val, index, end, true /* checked */);
     }
 
     public static int codePointBeforeSB(byte[] val, int index) {
-        checkOffset(index, val.length >> 1);
-        return codePointBefore(val, index);
+        return codePointBefore(val, index, true /* checked */);
     }
 
     public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
-        checkOffset(endIndex, val.length >> 1);
-        return codePointCount(val, beginIndex, endIndex);
+        return codePointCount(val, beginIndex, endIndex, true /* checked */);
+    }
+
+    public static int getChars(int i, int begin, int end, byte[] value) {
+        checkBoundsBeginEnd(begin, end, value);
+        int pos = getChars(i, end, value);
+        assert begin == pos;
+        return pos;
+    }
+
+    public static int getChars(long l, int begin, int end, byte[] value) {
+        checkBoundsBeginEnd(begin, end, value);
+        int pos = getChars(l, end, value);
+        assert begin == pos;
+        return pos;
+    }
+
+    public static boolean contentEquals(byte[] v1, byte[] v2, int len) {
+        checkBoundsOffCount(0, len, v2);
+        for (int i = 0; i < len; i++) {
+            if ((char)(v1[i] & 0xff) != getChar(v2, i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean contentEquals(byte[] value, CharSequence cs, int len) {
+        checkOffset(len, value);
+        for (int i = 0; i < len; i++) {
+            if (getChar(value, i) != cs.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) {
+        int end = i + 4;
+        checkBoundsBeginEnd(i, end, value);
+        putChar(value, i++, c1);
+        putChar(value, i++, c2);
+        putChar(value, i++, c3);
+        putChar(value, i++, c4);
+        assert(i == end);
+        return end;
+    }
+
+    public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) {
+        int end = i + 5;
+        checkBoundsBeginEnd(i, end, value);
+        putChar(value, i++, c1);
+        putChar(value, i++, c2);
+        putChar(value, i++, c3);
+        putChar(value, i++, c4);
+        putChar(value, i++, c5);
+        assert(i == end);
+        return end;
+    }
+
+    public static char charAt(byte[] value, int index) {
+        checkIndex(index, value);
+        return getChar(value, index);
+    }
+
+    public static void reverse(byte[] val, int count) {
+        checkOffset(count, val);
+        int n = count - 1;
+        boolean hasSurrogates = false;
+        for (int j = (n-1) >> 1; j >= 0; j--) {
+            int k = n - j;
+            char cj = getChar(val, j);
+            char ck = getChar(val, k);
+            putChar(val, j, ck);
+            putChar(val, k, cj);
+            if (Character.isSurrogate(cj) ||
+                Character.isSurrogate(ck)) {
+                hasSurrogates = true;
+            }
+        }
+        if (hasSurrogates) {
+            reverseAllValidSurrogatePairs(val, count);
+        }
+    }
+
+    /** Outlined helper method for reverse() */
+    private static void reverseAllValidSurrogatePairs(byte[] val, int count) {
+        for (int i = 0; i < count - 1; i++) {
+            char c2 = getChar(val, i);
+            if (Character.isLowSurrogate(c2)) {
+                char c1 = getChar(val, i + 1);
+                if (Character.isHighSurrogate(c1)) {
+                    putChar(val, i++, c1);
+                    putChar(val, i, c2);
+                }
+            }
+        }
+    }
+
+    // inflatedCopy byte[] -> byte[]
+    public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
+        // We need a range check here because 'putChar' has no checks
+        checkBoundsOffCount(dstOff, len, dst);
+        for (int i = 0; i < len; i++) {
+            putChar(dst, dstOff++, src[srcOff++] & 0xff);
+        }
+    }
+
+    // srcCoder == UTF16 && tgtCoder == LATIN1
+    public static int lastIndexOfLatin1(byte[] src, int srcCount,
+                                        byte[] tgt, int tgtCount, int fromIndex) {
+        assert fromIndex >= 0;
+        assert tgtCount > 0;
+        assert tgtCount <= tgt.length;
+        int min = tgtCount - 1;
+        int i = min + fromIndex;
+        int strLastIndex = tgtCount - 1;
+
+        char strLastChar = (char)(tgt[strLastIndex] & 0xff);
+
+        checkIndex(i, src);
+
+    startSearchForLastChar:
+        while (true) {
+            while (i >= min && getChar(src, i) != strLastChar) {
+                i--;
+            }
+            if (i < min) {
+                return -1;
+            }
+            int j = i - 1;
+            int start = j - strLastIndex;
+            int k = strLastIndex - 1;
+            while (j > start) {
+                if (getChar(src, j--) != (tgt[k--] & 0xff)) {
+                    i--;
+                    continue startSearchForLastChar;
+                }
+            }
+            return start + 1;
+        }
     }
 
     ////////////////////////////////////////////////////////////////
@@ -975,4 +1186,123 @@
     }
 
     static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
+
+    // Used by trusted callers.  Assumes all necessary bounds checks have
+    // been done by the caller.
+
+    /**
+     * This is a variant of {@link Integer#getChars(int, int, byte[])}, but for
+     * UTF-16 coder.
+     *
+     * @param i     value to convert
+     * @param index next index, after the least significant digit
+     * @param buf   target buffer, UTF16-coded.
+     * @return index of the most significant digit or minus sign, if present
+     */
+    static int getChars(int i, int index, byte[] buf) {
+        int q, r;
+        int charPos = index;
+
+        boolean negative = (i < 0);
+        if (!negative) {
+            i = -i;
+        }
+
+        // Get 2 digits/iteration using ints
+        while (i <= -100) {
+            q = i / 100;
+            r = (q * 100) - i;
+            i = q;
+            putChar(buf, --charPos, Integer.DigitOnes[r]);
+            putChar(buf, --charPos, Integer.DigitTens[r]);
+        }
+
+        // We know there are at most two digits left at this point.
+        q = i / 10;
+        r = (q * 10) - i;
+        putChar(buf, --charPos, '0' + r);
+
+        // Whatever left is the remaining digit.
+        if (q < 0) {
+            putChar(buf, --charPos, '0' - q);
+        }
+
+        if (negative) {
+            putChar(buf, --charPos, '-');
+        }
+        return charPos;
+    }
+
+    /**
+     * This is a variant of {@link Long#getChars(long, int, byte[])}, but for
+     * UTF-16 coder.
+     *
+     * @param i     value to convert
+     * @param index next index, after the least significant digit
+     * @param buf   target buffer, UTF16-coded.
+     * @return index of the most significant digit or minus sign, if present
+     */
+    static int getChars(long i, int index, byte[] buf) {
+        long q;
+        int r;
+        int charPos = index;
+
+        boolean negative = (i < 0);
+        if (!negative) {
+            i = -i;
+        }
+
+        // Get 2 digits/iteration using longs until quotient fits into an int
+        while (i <= Integer.MIN_VALUE) {
+            q = i / 100;
+            r = (int)((q * 100) - i);
+            i = q;
+            putChar(buf, --charPos, Integer.DigitOnes[r]);
+            putChar(buf, --charPos, Integer.DigitTens[r]);
+        }
+
+        // Get 2 digits/iteration using ints
+        int q2;
+        int i2 = (int)i;
+        while (i2 <= -100) {
+            q2 = i2 / 100;
+            r  = (q2 * 100) - i2;
+            i2 = q2;
+            putChar(buf, --charPos, Integer.DigitOnes[r]);
+            putChar(buf, --charPos, Integer.DigitTens[r]);
+        }
+
+        // We know there are at most two digits left at this point.
+        q2 = i2 / 10;
+        r  = (q2 * 10) - i2;
+        putChar(buf, --charPos, '0' + r);
+
+        // Whatever left is the remaining digit.
+        if (q2 < 0) {
+            putChar(buf, --charPos, '0' - q2);
+        }
+
+        if (negative) {
+            putChar(buf, --charPos, '-');
+        }
+        return charPos;
+    }
+    // End of trusted methods.
+
+    public static void checkIndex(int off, byte[] val) {
+        String.checkIndex(off, length(val));
+    }
+
+    public static void checkOffset(int off, byte[] val) {
+        String.checkOffset(off, length(val));
+    }
+
+    public static void checkBoundsBeginEnd(int begin, int end, byte[] val) {
+        String.checkBoundsBeginEnd(begin, end, length(val));
+    }
+
+    public static void checkBoundsOffCount(int offset, int count, byte[] val) {
+        String.checkBoundsOffCount(offset, count, length(val));
+    }
+
 }
--- a/src/java.base/unix/classes/java/lang/ProcessImpl.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/unix/classes/java/lang/ProcessImpl.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -617,7 +617,7 @@
     }
 
     @Override
-    public long getPid() {
+    public long pid() {
         return pid;
     }
 
--- a/src/java.base/windows/classes/java/lang/ProcessImpl.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/java.base/windows/classes/java/lang/ProcessImpl.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -523,7 +523,7 @@
 
     @Override
     public CompletableFuture<Process> onExit() {
-        return ProcessHandleImpl.completion(getPid(), false)
+        return ProcessHandleImpl.completion(pid(), false)
                 .handleAsync((exitStatus, unusedThrowable) -> this);
     }
 
@@ -550,8 +550,8 @@
     private static native void terminateProcess(long handle);
 
     @Override
-    public long getPid() {
-        return processHandle.getPid();
+    public long pid() {
+        return processHandle.pid();
     }
 
     private static native int getProcessId0(long handle);
@@ -572,7 +572,7 @@
     @Override
     public String toString() {
         int exitCode = getExitCodeProcess(handle);
-        return new StringBuilder("Process[pid=").append(getPid())
+        return new StringBuilder("Process[pid=").append(pid())
                 .append(", exitValue=").append(exitCode == STILL_ACTIVE ? "\"not exited\"" : exitCode)
                 .append("]").toString();
     }
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Exchange.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Exchange.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -26,6 +26,7 @@
 package jdk.incubator.http;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.net.InetSocketAddress;
 import java.net.ProxySelector;
 import java.net.SocketPermission;
@@ -64,6 +65,9 @@
     final HttpRequestImpl request;
     final HttpClientImpl client;
     volatile ExchangeImpl<T> exchImpl;
+    // used to record possible cancellation raised before the exchImpl
+    // has been established.
+    private volatile IOException failed;
     final List<SocketPermission> permissions = new LinkedList<>();
     final AccessControlContext acc;
     final MultiExchange<?,T> multi;
@@ -143,14 +147,80 @@
     }
 
     public void cancel() {
+        // cancel can be called concurrently before or at the same time
+        // that the exchange impl is being established.
+        // In that case we won't be able to propagate the cancellation
+        // right away
         if (exchImpl != null) {
             exchImpl.cancel();
+        } else {
+            // no impl - can't cancel impl yet.
+            // call cancel(IOException) instead which takes care
+            // of race conditions between impl/cancel.
+            cancel(new IOException("Request cancelled"));
         }
     }
 
     public void cancel(IOException cause) {
-        if (exchImpl != null) {
-            exchImpl.cancel(cause);
+        // If the impl is non null, propagate the exception right away.
+        // Otherwise record it so that it can be propagated once the
+        // exchange impl has been established.
+        ExchangeImpl<?> impl = exchImpl;
+        if (impl != null) {
+            // propagate the exception to the impl
+            impl.cancel(cause);
+        } else {
+            try {
+                // no impl yet. record the exception
+                failed = cause;
+                // now call checkCancelled to recheck the impl.
+                // if the failed state is set and the impl is not null, reset
+                // the failed state and propagate the exception to the impl.
+                checkCancelled(false);
+            } catch (IOException x) {
+                // should not happen - we passed 'false' above
+                throw new UncheckedIOException(x);
+            }
+        }
+    }
+
+    // This method will raise an exception if one was reported and if
+    // it is possible to do so. If the exception can be raised, then
+    // the failed state will be reset. Otherwise, the failed state
+    // will persist until the exception can be raised and the failed state
+    // can be cleared.
+    // Takes care of possible race conditions.
+    private void checkCancelled(boolean throwIfNoImpl) throws IOException {
+        ExchangeImpl<?> impl = null;
+        IOException cause = null;
+        if (failed != null) {
+            synchronized(this) {
+                cause = failed;
+                impl = exchImpl;
+                if (throwIfNoImpl || impl != null) {
+                    // The exception will be raised by one of the two methods
+                    // below: reset the failed state.
+                    failed = null;
+                }
+            }
+        }
+        if (cause == null) return;
+        if (impl != null) {
+            // The exception is raised by propagating it to the impl.
+            impl.cancel(cause);
+        } else if (throwIfNoImpl) {
+            // The exception is raised by throwing it immediately
+            throw cause;
+        } else {
+            Log.logTrace("Exchange: request [{0}/timeout={1}ms] no impl is set."
+                         + "\n\tCan''t cancel yet with {2}",
+                         request.uri(),
+                         request.duration() == null ? -1 :
+                         // calling duration.toMillis() can throw an exception.
+                         // this is just debugging, we don't care if it overflows.
+                         (request.duration().getSeconds() * 1000
+                          + request.duration().getNano() / 1000000),
+                         cause);
         }
     }
 
@@ -191,10 +261,26 @@
         }
     }
 
+    // get/set the exchange impl, solving race condition issues with
+    // potential concurrent calls to cancel() or cancel(IOException)
+    private void establishExchange(HttpConnection connection)
+        throws IOException, InterruptedException
+    {
+        // check if we have been cancelled first.
+        checkCancelled(true);
+        // not yet cancelled: create/get a new impl
+        exchImpl = ExchangeImpl.get(this, connection);
+        // recheck for cancelled, in case of race conditions
+        checkCancelled(true);
+        // now we're good to go. because exchImpl is no longer null
+        // cancel() will be able to propagate directly to the impl
+        // after this point.
+    }
+
     private Response responseImpl0(HttpConnection connection)
         throws IOException, InterruptedException
     {
-        exchImpl = ExchangeImpl.get(this, connection);
+        establishExchange(connection);
         exchImpl.setClientForRequest(requestProcessor);
         if (request.expectContinue()) {
             Log.logTrace("Sending Expect: 100-Continue");
@@ -257,7 +343,7 @@
 
     CompletableFuture<Response> responseAsyncImpl0(HttpConnection connection) {
         try {
-            exchImpl = ExchangeImpl.get(this, connection);
+            establishExchange(connection);
         } catch (IOException | InterruptedException e) {
             return MinimalFuture.failedFuture(e);
         }
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Http1Exchange.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Http1Exchange.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -46,9 +46,12 @@
 class Http1Exchange<T> extends ExchangeImpl<T> {
 
     final HttpRequestImpl request;        // main request
-    final List<CompletableFuture<?>> operations; // used for cancel
+    private final List<CompletableFuture<?>> operations; // used for cancel
     final Http1Request requestAction;
-    volatile Http1Response<T> response;
+    private volatile Http1Response<T> response;
+    // use to record possible cancellation raised before any operation
+    // has been initiated.
+    private IOException failed;
     final HttpConnection connection;
     final HttpClientImpl client;
     final Executor executor;
@@ -70,7 +73,7 @@
         this.request = exchange.request();
         this.client = exchange.client();
         this.executor = exchange.executor();
-        this.operations = Collections.synchronizedList(new LinkedList<>());
+        this.operations = new LinkedList<>();
         this.buffer = exchange.getBuffer();
         if (connection != null) {
             this.connection = connection;
@@ -186,9 +189,22 @@
         }
         connection.close();
         int count = 0;
-        for (CompletableFuture<?> cf : operations) {
-            cf.completeExceptionally(cause);
-            count++;
+        if (operations.isEmpty()) {
+            failed = cause;
+            Log.logTrace("Http1Exchange: request [{0}/timeout={1}ms] no pending operation."
+                         + "\n\tCan''t cancel yet with {2}",
+                         request.uri(),
+                         request.duration() == null ? -1 :
+                         // calling duration.toMillis() can throw an exception.
+                         // this is just debugging, we don't care if it overflows.
+                         (request.duration().getSeconds() * 1000
+                          + request.duration().getNano() / 1000000),
+                         cause);
+        } else {
+            for (CompletableFuture<?> cf : operations) {
+                cf.completeExceptionally(cause);
+                count++;
+            }
         }
         Log.logError("Http1Exchange.cancel: count=" + count);
     }
@@ -206,8 +222,24 @@
         CompletableFuture<Response> cf =
             connection.whenReceivingResponse()
                       .thenCompose((v) -> getResponseAsyncImpl(executor));
-
-        operations.add(cf);
+        IOException cause;
+        synchronized(this) {
+            operations.add(cf);
+            cause = failed;
+            failed = null;
+        }
+        if (cause != null) {
+            Log.logTrace("Http1Exchange: request [{0}/timeout={1}ms]"
+                         + "\n\tCompleting exceptionally with {2}\n",
+                         request.uri(),
+                         request.duration() == null ? -1 :
+                         // calling duration.toMillis() can throw an exception.
+                         // this is just debugging, we don't care if it overflows.
+                         (request.duration().getSeconds() * 1000
+                          + request.duration().getNano() / 1000000),
+                         cause);
+            cf.completeExceptionally(cause);
+        }
         return cf;
     }
 }
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpClientImpl.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpClientImpl.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -582,12 +582,14 @@
     // Timers are implemented through timed Selector.select() calls.
 
     synchronized void registerTimer(TimeoutEvent event) {
+        Log.logTrace("Registering timer {0}", event);
         timeouts.add(event);
         selmgr.wakeupSelector();
     }
 
     synchronized void cancelTimer(TimeoutEvent event) {
-        timeouts.stream().filter(e -> e == event).forEach(timeouts::remove);
+        Log.logTrace("Canceling timer {0}", event);
+        timeouts.remove(event);
     }
 
     /**
@@ -595,23 +597,61 @@
      * returns the amount of time, in milliseconds, until the next earliest
      * event. A return value of 0 means that there are no events.
      */
-    private synchronized long purgeTimeoutsAndReturnNextDeadline() {
-        if (timeouts.isEmpty())
-            return 0L;
+    private long purgeTimeoutsAndReturnNextDeadline() {
+        long diff = 0L;
+        List<TimeoutEvent> toHandle = null;
+        int remaining = 0;
+        // enter critical section to retrieve the timeout event to handle
+        synchronized(this) {
+            if (timeouts.isEmpty()) return 0L;
 
-        Instant now = Instant.now();
-        Iterator<TimeoutEvent> itr = timeouts.iterator();
-        while (itr.hasNext()) {
-            TimeoutEvent event = itr.next();
-            long diff = now.until(event.deadline(), ChronoUnit.MILLIS);
-            if (diff <= 0) {
-                itr.remove();
-                event.handle();  // TODO: release lock.
-            } else {
-                return diff;
+            Instant now = Instant.now();
+            Iterator<TimeoutEvent> itr = timeouts.iterator();
+            while (itr.hasNext()) {
+                TimeoutEvent event = itr.next();
+                diff = now.until(event.deadline(), ChronoUnit.MILLIS);
+                if (diff <= 0) {
+                    itr.remove();
+                    toHandle = (toHandle == null) ? new ArrayList<>() : toHandle;
+                    toHandle.add(event);
+                } else {
+                    break;
+                }
             }
+            remaining = timeouts.size();
         }
-        return 0L;
+
+        // can be useful for debugging
+        if (toHandle != null && Log.trace()) {
+            Log.logTrace("purgeTimeoutsAndReturnNextDeadline: handling "
+                    + (toHandle == null ? 0 : toHandle.size()) + " events, "
+                    + "remaining " + remaining
+                    + ", next deadline: " + (diff < 0 ? 0L : diff));
+        }
+
+        // handle timeout events out of critical section
+        if (toHandle != null) {
+            Throwable failed = null;
+            for (TimeoutEvent event : toHandle) {
+                try {
+                   Log.logTrace("Firing timer {0}", event);
+                   event.handle();
+                } catch (Error | RuntimeException e) {
+                    // Not expected. Handle remaining events then throw...
+                    // If e is an OOME or SOE it might simply trigger a new
+                    // error from here - but in this case there's not much we
+                    // could do anyway. Just let it flow...
+                    if (failed == null) failed = e;
+                    else failed.addSuppressed(e);
+                    Log.logTrace("Failed to handle event {0}: {1}", event, e);
+                }
+            }
+            if (failed instanceof Error) throw (Error) failed;
+            if (failed instanceof RuntimeException) throw (RuntimeException) failed;
+        }
+
+        // return time to wait until next event. 0L if there's no more events.
+        return diff < 0 ? 0L : diff;
     }
 
     // used for the connection window
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/MultiExchange.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/MultiExchange.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -357,9 +357,5 @@
         public void handle() {
             cancel(new HttpTimeoutException("request timed out"));
         }
-        @Override
-        public String toString() {
-            return "[deadline = " + deadline() + "]";
-        }
     }
 }
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/PlainHttpConnection.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/PlainHttpConnection.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -54,7 +54,7 @@
  */
 class PlainHttpConnection extends HttpConnection implements AsyncConnection {
 
-    protected SocketChannel chan;
+    protected final SocketChannel chan;
     private volatile boolean connected;
     private boolean closed;
 
@@ -100,6 +100,7 @@
                 chan.finishConnect();
             } catch (IOException e) {
                 cf.completeExceptionally(e);
+                return;
             }
             connected = true;
             cf.complete(null);
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Stream.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Stream.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -670,11 +670,21 @@
 
     @Override
     CompletableFuture<Response> getResponseAsync(Executor executor) {
-        CompletableFuture<Response> cf;
+        CompletableFuture<Response> cf = null;
+        // The code below deals with race condition that can be caused when
+        // completeResponse() is being called before getResponseAsync()
         synchronized (response_cfs) {
             if (!response_cfs.isEmpty()) {
+                // This CompletableFuture was created by completeResponse().
+                // it will be already completed.
                 cf = response_cfs.remove(0);
+                // if we find a cf here it should be already completed.
+                // finding a non completed cf should not happen. just assert it.
+                assert cf.isDone() : "Removing uncompleted response: could cause code to hang!";
             } else {
+                // getResponseAsync() is called first. Create a CompletableFuture
+                // that will be completed by completeResponse() when
+                // completeResponse() is called.
                 cf = new MinimalFuture<>();
                 response_cfs.add(cf);
             }
@@ -708,7 +718,7 @@
                     cf.complete(resp);
                     response_cfs.remove(cf);
                     return;
-                }
+                } // else we found the previous response: just leave it alone.
             }
             cf = MinimalFuture.completedFuture(resp);
             Log.logTrace("Created completed future (streamid={0}): {1}",
@@ -742,10 +752,13 @@
      */
     void completeResponseExceptionally(Throwable t) {
         synchronized (response_cfs) {
-            for (CompletableFuture<Response> cf : response_cfs) {
+            // use index to avoid ConcurrentModificationException
+            // caused by removing the CF from within the loop.
+            for (int i = 0; i < response_cfs.size(); i++) {
+                CompletableFuture<Response> cf = response_cfs.get(i);
                 if (!cf.isDone()) {
                     cf.completeExceptionally(t);
-                    response_cfs.remove(cf);
+                    response_cfs.remove(i);
                     return;
                 }
             }
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/TimeoutEvent.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/TimeoutEvent.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -27,10 +27,11 @@
 
 import java.time.Duration;
 import java.time.Instant;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Timeout event notified by selector thread. Executes the given handler if
- * the timer not cancelled first.
+ * the timer not canceled first.
  *
  * Register with {@link HttpClientImpl#registerTimer(TimeoutEvent)}.
  *
@@ -38,6 +39,10 @@
  */
 abstract class TimeoutEvent implements Comparable<TimeoutEvent> {
 
+    private static final AtomicLong COUNTER = new AtomicLong();
+    // we use id in compareTo to make compareTo consistent with equals
+    // see TimeoutEvent::compareTo below;
+    private final long id = COUNTER.incrementAndGet();
     private final Instant deadline;
 
     TimeoutEvent(Duration duration) {
@@ -52,6 +57,24 @@
 
     @Override
     public int compareTo(TimeoutEvent other) {
-        return this.deadline.compareTo(other.deadline);
+        if (other == this) return 0;
+        // if two events have the same deadline, but are not equals, then the
+        // smaller is the one that was created before (has the smaller id).
+        // This is arbitrary and we don't really care which is smaller or
+        // greater, but we need a total order, so two events with the
+        // same deadline cannot compare == 0 if they are not equals.
+        final int compareDeadline = this.deadline.compareTo(other.deadline);
+        if (compareDeadline == 0 && !this.equals(other)) {
+            long diff = this.id - other.id; // should take care of wrap around
+            if (diff < 0) return -1;
+            else if (diff > 0) return 1;
+            else assert false : "Different events with same id and deadline";
+        }
+        return compareDeadline;
+    }
+
+    @Override
+    public String toString() {
+        return "TimeoutEvent[id=" + id + ", deadline=" + deadline + "]";
     }
 }
--- a/src/jdk.management/share/classes/com/sun/management/VMOption.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/src/jdk.management/share/classes/com/sun/management/VMOption.java	Thu Apr 13 16:27:18 2017 +0000
@@ -47,8 +47,6 @@
  * object was constructed.  The value of the VM option
  * may be changed after the {@code VMOption} object was constructed,
  *
- * @see <a href="{@docRoot}/../../../../technotes/guides/vm/index.html">
- *         Java Virtual Machine</a>
  * @author Mandy Chung
  * @since 1.6
  */
--- a/test/ProblemList.txt	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/ProblemList.txt	Thu Apr 13 16:27:18 2017 +0000
@@ -170,8 +170,6 @@
 
 java/net/DatagramSocket/SendDatagramToBadAddress.java           7143960 macosx-all
 
-java/net/httpclient/TimeoutOrdering.java                        8170940 solaris-all,windows-all
-
 ############################################################################
 
 # jdk_nio
--- a/test/com/sun/jdi/ProcessAttachTest.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/com/sun/jdi/ProcessAttachTest.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,13 +23,11 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.List;
 import java.util.Map;
 
 import jdk.testlibrary.ProcessTools;
 
 import com.sun.jdi.Bootstrap;
-import com.sun.jdi.ThreadReference;
 import com.sun.jdi.VirtualMachine;
 import com.sun.jdi.connect.AttachingConnector;
 import com.sun.jdi.connect.Connector;
@@ -86,7 +84,7 @@
             is.read();
 
             // Attach a debugger
-            tryDebug(p.getPid());
+            tryDebug(p.pid());
         } finally {
             p.destroyForcibly();
         }
--- a/test/java/io/FilePermission/Correctness.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/io/FilePermission/Correctness.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -89,12 +89,14 @@
         //check("/-", "-");
 
         try {
-            // containsPath is broken on Windows.
             containsMethod = FilePermission.class.getDeclaredMethod(
                     "containsPath", Path.class, Path.class);
             containsMethod.setAccessible(true);
             System.out.println();
 
+            // The 1st 2 args of contains() must be normalized paths.
+            // When FilePermission::containsPath is called by implies,
+            // paths have already been normalized.
             contains("x", "x", 0);
             contains("x", "x/y", 1);
             contains("x", "x/y/z", 2);
@@ -160,7 +162,7 @@
         }
     }
 
-    static void check(String s1, String s2, boolean expected) {
+    static void check0(String s1, String s2, boolean expected) {
         FilePermission fp1 = new FilePermission(s1, "read");
         FilePermission fp2 = new FilePermission(s2, "read");
         boolean b = fp1.implies(fp2);
@@ -173,6 +175,16 @@
         }
     }
 
+    static void check(String s1, String s2, boolean expected) {
+        check0(s1, s2, expected);
+        if (isWindows) {
+            check0("C:" + s1, s2, false);
+            check0(s1, "C:" + s2, false);
+            check0("C:" + s1, "D:" + s2, false);
+            check0("C:" + s1, "C:" + s2, expected);
+        }
+    }
+
     static void check(String s1, String s2) {
         check(s1, s2, true);
     }
--- a/test/java/lang/ProcessBuilder/Basic.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/ProcessBuilder/Basic.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -311,7 +311,7 @@
             if (action.equals("sleep")) {
                 Thread.sleep(10 * 60 * 1000L);
             } else if (action.equals("pid")) {
-                System.out.println(ProcessHandle.current().getPid());
+                System.out.println(ProcessHandle.current().pid());
             } else if (action.equals("testIO")) {
                 String expected = "standard input";
                 char[] buf = new char[expected.length()+1];
@@ -1235,7 +1235,7 @@
             Process p = pb.start();
             String s = commandOutput(p);
             long actualPid = Long.valueOf(s.trim());
-            long expectedPid = p.getPid();
+            long expectedPid = p.pid();
             equal(actualPid, expectedPid);
         } catch (Throwable t) {
             unexpected(t);
@@ -1245,7 +1245,7 @@
         // Test the default implementation of Process.getPid
         DelegatingProcess p = new DelegatingProcess(null);
         THROWS(UnsupportedOperationException.class,
-                () -> p.getPid(),
+                () -> p.pid(),
                 () -> p.toHandle(),
                 () -> p.supportsNormalTermination(),
                 () -> p.children(),
@@ -2243,7 +2243,7 @@
                 // Child process waits until it gets input
                 String s = p.toString();
                 check(s.contains("not exited"));
-                check(s.contains("pid=" + p.getPid() + ","));
+                check(s.contains("pid=" + p.pid() + ","));
 
                 new PrintStream(p.getOutputStream()).print("standard input");
                 p.getOutputStream().close();
@@ -2251,7 +2251,7 @@
                 // Check the toString after it exits
                 int exitValue = p.waitFor();
                 s = p.toString();
-                check(s.contains("pid=" + p.getPid() + ","));
+                check(s.contains("pid=" + p.pid() + ","));
                 check(s.contains("exitValue=" + exitValue) &&
                         !s.contains("not exited"));
             }
--- a/test/java/lang/ProcessBuilder/PipelineTest.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/ProcessBuilder/PipelineTest.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -212,7 +212,7 @@
 
     static void print(ProcessHandle p) {
         System.out.printf("process: pid: %d, info: %s%n",
-                p.getPid(), p.info());
+                p.pid(), p.info());
     }
 
     // Check various aspects of the processes
--- a/test/java/lang/ProcessBuilder/Zombies.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/ProcessBuilder/Zombies.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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,7 +43,7 @@
             ! new File("/bin/ps").canExecute())
             return;
         System.out.println("Looks like a Unix system.");
-        long mypid = ProcessHandle.current().getPid();
+        long mypid = ProcessHandle.current().pid();
         System.out.printf("mypid: %d%n", mypid);
 
         final Runtime rt = Runtime.getRuntime();
@@ -65,7 +65,7 @@
 
         Process p = rt.exec(TrueCommand);
         ProcessHandle pp = p.toHandle().parent().orElse(null);
-        System.out.printf("%s pid: %d, parent: %s%n", TrueCommand, p.getPid(), pp);
+        System.out.printf("%s pid: %d, parent: %s%n", TrueCommand, p.pid(), pp);
         p.waitFor();
 
         // Count all the zombies that are children of this Java process
--- a/test/java/lang/ProcessHandle/Basic.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/ProcessHandle/Basic.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -66,13 +66,13 @@
     public static void test2() {
         try {
             ProcessHandle self = ProcessHandle.current();
-            long pid = self.getPid();       // known native process id
+            long pid = self.pid();       // known native process id
             Optional<ProcessHandle> self1 = ProcessHandle.of(pid);
             assertEquals(self1.get(), self,
-                    "ProcessHandle.of(x.getPid()) should be equal getPid() %d: %d");
+                    "ProcessHandle.of(x.pid()) should be equal pid() %d: %d");
 
             Optional<ProcessHandle> ph = ProcessHandle.of(pid);
-            assertEquals(pid, ph.get().getPid());
+            assertEquals(pid, ph.get().pid());
         } finally {
             // Cleanup any left over processes
             ProcessHandle.current().children().forEach(ProcessHandle::destroy);
@@ -98,7 +98,7 @@
             Process p = new ProcessBuilder("sleep", "0").start();
             p.waitFor();
 
-            long deadPid = p.getPid();
+            long deadPid = p.pid();
             p = null;               // Forget the process
 
             Optional<ProcessHandle> t = ProcessHandle.of(deadPid);
--- a/test/java/lang/ProcessHandle/JavaChild.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/ProcessHandle/JavaChild.java	Thu Apr 13 16:27:18 2017 +0000
@@ -159,7 +159,7 @@
      */
     CompletableFuture<String> forEachOutputLine(Consumer<String> consumer) {
         final CompletableFuture<String> future = new CompletableFuture<>();
-        String name = "OutputLineReader-" + getPid();
+        String name = "OutputLineReader-" + pid();
         Thread t = new Thread(() -> {
             try (BufferedReader reader = outputReader()) {
                 String line;
@@ -167,7 +167,7 @@
                     consumer.accept(line);
                 }
             } catch (IOException | RuntimeException ex) {
-                consumer.accept("IOE (" + getPid() + "):" + ex.getMessage());
+                consumer.accept("IOE (" + pid() + "):" + ex.getMessage());
                 future.completeExceptionally(ex);
             }
             future.complete("success");
@@ -327,7 +327,7 @@
                                 try {
                                     p.getOutputStream().close();
                                 } catch (IOException ie) {
-                                    sendResult("stdin_closing", p.getPid(),
+                                    sendResult("stdin_closing", p.pid(),
                                             "exception", ie.getMessage());
                                 }
                             }
@@ -352,9 +352,9 @@
                                             "children to terminate%n");
                                     children.removeAll(completedChildren);
                                     for (JavaChild c : children) {
-                                        sendResult("stdin_noterm", c.getPid());
+                                        sendResult("stdin_noterm", c.pid());
                                         System.err.printf("  Process not terminated: " +
-                                                "pid: %d%n", c.getPid());
+                                                "pid: %d%n", c.pid());
                                     }
                                     System.exit(2);
                                 }
@@ -386,11 +386,11 @@
                         System.arraycopy(args, nextArg, subargs, 0, subargs.length);
                         for (int i = 0; i < ncount; i++) {
                             JavaChild p = spawnJavaChild(subargs);
-                            sendResult(action, p.getPid());
+                            sendResult(action, p.pid());
                             p.forEachOutputLine(JavaChild::sendRaw);
                             p.onJavaChildExit().thenAccept((p1) -> {
                                 int excode = p1.exitValue();
-                                sendResult("child_exit", p1.getPid(), excode);
+                                sendResult("child_exit", p1.pid(), excode);
                                 completedChildren.add(p1);
                             });
                             children.add(p);        // Add child to spawned list
@@ -410,7 +410,7 @@
                             if (p.isAlive()) {
                                 sentCount++;
                                 // overwrite with current pid
-                                result[0] = Long.toString(p.getPid());
+                                result[0] = Long.toString(p.pid());
                                 sendResult(action, result);
                                 p.sendAction(args[nextArg], subargs);
                             }
@@ -426,7 +426,7 @@
                         // ignoring those that are not alive
                         for (JavaChild p : children) {
                             if (p.isAlive()) {
-                                sendResult(action, p.getPid());
+                                sendResult(action, p.pid());
                                 p.getOutputStream().close();
                             }
                         }
@@ -505,7 +505,7 @@
         String command;
         Object[] results;
         Event(String command, Object... results) {
-            this(self.getPid(), ++commandSeq, command, results);
+            this(self.pid(), ++commandSeq, command, results);
         }
         Event(long pid, int seq, String command, Object... results) {
             this.pid = pid;
--- a/test/java/lang/ProcessHandle/OnExitTest.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/ProcessHandle/OnExitTest.java	Thu Apr 13 16:27:18 2017 +0000
@@ -104,7 +104,7 @@
 
             JavaChild proc = JavaChild.spawnJavaChild("stdin");
             procHandle = proc.toHandle();
-            printf(" spawned: %d%n", proc.getPid());
+            printf(" spawned: %d%n", proc.pid());
 
             proc.forEachOutputLine((s) -> {
                 String[] split = s.trim().split(" ");
@@ -235,7 +235,7 @@
                 } while (!"pid".equals(split[1]));
 
                 // Tell B to wait for A's pid
-                B.sendAction("waitpid", A.getPid());
+                B.sendAction("waitpid", A.pid());
 
                 // Wait a bit to see if B will prematurely report the termination of A
                 try {
--- a/test/java/lang/ProcessHandle/ProcessUtil.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/ProcessHandle/ProcessUtil.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -199,7 +199,7 @@
      */
     static void printProcess(ProcessHandle ph, String prefix) {
         printf("%spid %s, alive: %s; parent: %s, %s%n", prefix,
-                ph.getPid(), ph.isAlive(), ph.parent(), ph.info());
+                ph.pid(), ph.isAlive(), ph.parent(), ph.info());
     }
 
     /**
--- a/test/java/lang/ProcessHandle/TreeTest.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/ProcessHandle/TreeTest.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -73,7 +73,7 @@
         try {
             ProcessHandle self = ProcessHandle.current();
 
-            printf("self pid: %d%n", self.getPid());
+            printf("self pid: %d%n", self.pid());
             printDeep(self, "");
 
             for (int i = 0; i < MAXCHILDREN; i++) {
@@ -154,7 +154,7 @@
 
             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
             ProcessHandle p1Handle = p1.toHandle();
-            printf("  p1 pid: %d%n", p1.getPid());
+            printf("  p1 pid: %d%n", p1.pid());
 
             // Gather the PIDs from the output of the spawing process
             p1.forEachOutputLine((s) -> {
@@ -206,7 +206,7 @@
             // show the complete list of children (for debug)
             List<ProcessHandle> descendants = getDescendants(p1Handle);
             printf(" descendants:  %s%n",
-                    descendants.stream().map(p -> p.getPid())
+                    descendants.stream().map(p -> p.pid())
                            .collect(Collectors.toList()));
 
             // Verify that all spawned children show up in the descendants  List
@@ -252,7 +252,7 @@
 
             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
             ProcessHandle p1Handle = p1.toHandle();
-            printf(" p1: %s%n", p1.getPid());
+            printf(" p1: %s%n", p1.pid());
 
             int newChildren = 3;
             CountDownLatch spawnCount = new CountDownLatch(newChildren);
@@ -356,11 +356,11 @@
             parent[sortindex[i]] = processes[sortindex[i]].parent().orElse(null);
         }
         Arrays.sort(sortindex, (i1, i2) -> {
-            int cmp = Long.compare((parent[i1] == null ? 0L : parent[i1].getPid()),
-                    (parent[i2] == null ? 0L : parent[i2].getPid()));
+            int cmp = Long.compare((parent[i1] == null ? 0L : parent[i1].pid()),
+                    (parent[i2] == null ? 0L : parent[i2].pid()));
             if (cmp == 0) {
-                cmp = Long.compare((processes[i1] == null ? 0L : processes[i1].getPid()),
-                        (processes[i2] == null ? 0L : processes[i2].getPid()));
+                cmp = Long.compare((processes[i1] == null ? 0L : processes[i1].pid()),
+                        (processes[i2] == null ? 0L : processes[i2].pid()));
             }
             return cmp;
         });
@@ -397,7 +397,7 @@
             ProcessHandle p1Handle = p1.toHandle();
 
             printf("Spawning %d x %d x %d processes, pid: %d%n",
-                    factor, factor, factor, p1.getPid());
+                    factor, factor, factor, p1.pid());
 
             // Start the first tier of subprocesses
             p1.sendAction("spawn", factor, "stdin");
@@ -448,7 +448,7 @@
 
             List<ProcessHandle> subprocesses = getDescendants(p1Handle);
             printf(" descendants:  %s%n",
-                    subprocesses.stream().map(p -> p.getPid())
+                    subprocesses.stream().map(p -> p.pid())
                     .collect(Collectors.toList()));
 
             p1.getOutputStream().close();  // Close stdin for the controlling p1
--- a/test/java/lang/Runtime/exec/SleepyCat.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/lang/Runtime/exec/SleepyCat.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,10 +80,10 @@
             for (Process p : pids) {
                 if (p == null)
                     continue;
-                String[] pfiles = {"pfiles", Long.toString(p.getPid())};
+                String[] pfiles = {"pfiles", Long.toString(p.pid())};
                 fds = new ProcessBuilder(pfiles).inheritIO().start();
                 fds.waitFor();
-                String[] pstack = {"pstack", Long.toString(p.getPid())};
+                String[] pstack = {"pstack", Long.toString(p.pid())};
                 fds = new ProcessBuilder(pstack).inheritIO().start();
                 fds.waitFor();
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/net/httpclient/SmallTimeout.java	Thu Apr 13 16:27:18 2017 +0000
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ *
+ * 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.net.ServerSocket;
+import java.net.URI;
+import jdk.incubator.http.HttpClient;
+import jdk.incubator.http.HttpRequest;
+import jdk.incubator.http.HttpResponse;
+import jdk.incubator.http.HttpTimeoutException;
+import java.time.Duration;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import static java.lang.System.out;
+import static jdk.incubator.http.HttpResponse.BodyHandler.discard;
+
+/**
+ * @test
+ * @bug 8178147
+ * @summary Ensures that small timeouts do not cause hangs due to race conditions
+ * @run main/othervm SmallTimeout
+ */
+
+// To enable logging use. Not enabled by default as it changes the dynamics
+// of the test.
+// @run main/othervm -Djdk.httpclient.HttpClient.log=all,frames:all SmallTimeout
+
+public class SmallTimeout {
+
+    static int[] TIMEOUTS = {2, 1, 3, 2, 100, 1};
+
+    // A queue for placing timed out requests so that their order can be checked.
+    static LinkedBlockingQueue<HttpRequest> queue = new LinkedBlockingQueue<>();
+
+    static volatile boolean error;
+
+    public static void main(String[] args) throws Exception {
+        HttpClient client = HttpClient.newHttpClient();
+
+        try (ServerSocket ss = new ServerSocket(0, 20)) {
+            int port = ss.getLocalPort();
+            URI uri = new URI("http://127.0.0.1:" + port + "/");
+
+            HttpRequest[] requests = new HttpRequest[TIMEOUTS.length];
+
+            out.println("--- TESTING Async");
+            for (int i = 0; i < TIMEOUTS.length; i++) {
+                requests[i] = HttpRequest.newBuilder(uri)
+                                         .timeout(Duration.ofMillis(TIMEOUTS[i]))
+                                         .GET()
+                                         .build();
+
+                final HttpRequest req = requests[i];
+                CompletableFuture<HttpResponse<Object>> response = client
+                    .sendAsync(req, discard(null))
+                    .whenComplete((HttpResponse<Object> r, Throwable t) -> {
+                        if (r != null) {
+                            out.println("Unexpected response: " + r);
+                            error = true;
+                        }
+                        if (t != null) {
+                            if (!(t.getCause() instanceof HttpTimeoutException)) {
+                                out.println("Wrong exception type:" + t.toString());
+                                Throwable c = t.getCause() == null ? t : t.getCause();
+                                c.printStackTrace();
+                                error = true;
+                            } else {
+                                out.println("Caught expected timeout: " + t.getCause());
+                            }
+                        }
+                        if (t == null && r == null) {
+                            out.println("Both response and throwable are null!");
+                            error = true;
+                        }
+                        queue.add(req);
+                    });
+            }
+            System.out.println("All requests submitted. Waiting ...");
+
+            checkReturn(requests);
+
+            if (error)
+                throw new RuntimeException("Failed. Check output");
+
+            // Repeat blocking in separate threads. Use queue to wait.
+            out.println("--- TESTING Sync");
+
+            // For running blocking response tasks
+            ExecutorService executor = Executors.newCachedThreadPool();
+
+            for (int i = 0; i < TIMEOUTS.length; i++) {
+                requests[i] = HttpRequest.newBuilder(uri)
+                                         .timeout(Duration.ofMillis(TIMEOUTS[i]))
+                                         .GET()
+                                         .build();
+
+                final HttpRequest req = requests[i];
+                executor.execute(() -> {
+                    try {
+                        client.send(req, discard(null));
+                    } catch (HttpTimeoutException e) {
+                        out.println("Caught expected timeout: " + e);
+                        queue.offer(req);
+                    } catch (IOException | InterruptedException ee) {
+                        Throwable c = ee.getCause() == null ? ee : ee.getCause();
+                        c.printStackTrace();
+                        error = true;
+                    }
+                });
+            }
+            System.out.println("All requests submitted. Waiting ...");
+
+            checkReturn(requests);
+
+            executor.shutdownNow();
+
+            if (error)
+                throw new RuntimeException("Failed. Check output");
+
+        } finally {
+            ((ExecutorService) client.executor()).shutdownNow();
+        }
+    }
+
+    static void checkReturn(HttpRequest[] requests) throws InterruptedException {
+        // wait for exceptions and check order
+        for (int j = 0; j < TIMEOUTS.length; j++) {
+            HttpRequest req = queue.take();
+            out.println("Got request from queue " + req + ", order: " + getRequest(req, requests));
+        }
+        out.println("Return ok");
+    }
+
+    /** Returns the index of the request in the array. */
+    static String getRequest(HttpRequest req, HttpRequest[] requests) {
+        for (int i=0; i<requests.length; i++) {
+            if (req == requests[i]) {
+                return "r" + i;
+            }
+        }
+        throw new AssertionError("Unknown request: " + req);
+    }
+}
--- a/test/java/net/httpclient/TimeoutOrdering.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/net/httpclient/TimeoutOrdering.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -43,6 +43,9 @@
  * @run main/othervm TimeoutOrdering
  */
 
+// To enable logging use
+// @run main/othervm -Djdk.httpclient.HttpClient.log=all,frames:all TimeoutOrdering
+
 public class TimeoutOrdering {
 
     // The assumption is that 5 secs is sufficiently large enough, without being
@@ -81,6 +84,8 @@
                         if (t != null) {
                             if (!(t.getCause() instanceof HttpTimeoutException)) {
                                 out.println("Wrong exception type:" + t.toString());
+                                Throwable c = t.getCause() == null ? t : t.getCause();
+                                c.printStackTrace();
                                 error = true;
                             } else {
                                 out.println("Caught expected timeout: " + t.getCause());
@@ -116,6 +121,8 @@
                         out.println("Caught expected timeout: " + e);
                         queue.offer(req);
                     } catch (IOException | InterruptedException ee) {
+                        Throwable c = ee.getCause() == null ? ee : ee.getCause();
+                        c.printStackTrace();
                         error = true;
                     }
                 });
--- a/test/java/util/logging/LoggingDeadlock2.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/java/util/logging/LoggingDeadlock2.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -263,7 +263,7 @@
                     sleep(ms);
                     System.err.println("Timeout reached: " + ms);
                     if (process.isAlive()) {
-                        long pid = process.getPid();
+                        long pid = process.pid();
                         ProcessBuilder jstack = new ProcessBuilder(jstackExe, String.valueOf(pid));
                         System.err.println("Dumping subprocess stack: " + pid);
                         Process p = jstack.inheritIO().start();
--- a/test/lib/testlibrary/jdk/testlibrary/ProcessThread.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/lib/testlibrary/jdk/testlibrary/ProcessThread.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -26,7 +26,6 @@
 import java.io.PrintWriter;
 
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 
 /**
@@ -195,7 +194,7 @@
          * @return The PID associated with this process runnable
          */
         public long getPid() throws InterruptedException {
-            return getProcess().getPid();
+            return getProcess().pid();
         }
 
         public void sendMessage(String message) throws InterruptedException {
--- a/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -256,7 +256,7 @@
      * @return Process id
      */
     public static long getProcessId() {
-        return ProcessHandle.current().getPid();
+        return ProcessHandle.current().pid();
     }
 
     /**
@@ -542,8 +542,8 @@
         }
 
         @Override
-        public long getPid() {
-            return p.getPid();
+        public long pid() {
+            return p.pid();
         }
 
         @Override
--- a/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -144,7 +144,7 @@
 
             System.out.println("Attaching test manager:");
             System.out.println("=========================");
-            System.out.println("  PID           : " + serverPrc.getPid());
+            System.out.println("  PID           : " + serverPrc.pid());
             System.out.println("  shutdown port : " + port.get());
 
             ProcessBuilder client = ProcessTools.createJavaProcessBuilder(
@@ -152,7 +152,7 @@
                 TEST_CLASSPATH,
                 "--add-exports", "jdk.management.agent/jdk.internal.agent=ALL-UNNAMED",
                 "TestManager",
-                String.valueOf(serverPrc.getPid()),
+                String.valueOf(serverPrc.pid()),
                 port.get(),
                 "true"
             );
--- a/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -129,7 +129,7 @@
 
             System.out.println("Attaching test manager:");
             System.out.println("=========================");
-            System.out.println("  PID           : " + serverPrc.getPid());
+            System.out.println("  PID           : " + serverPrc.pid());
             System.out.println("  shutdown port : " + port.get());
 
             ProcessBuilder client = ProcessTools.createJavaProcessBuilder(
@@ -137,7 +137,7 @@
                 TEST_CLASSPATH,
                 "--add-exports", "jdk.management.agent/jdk.internal.agent=ALL-UNNAMED",
                 "TestManager",
-                String.valueOf(serverPrc.getPid()),
+                String.valueOf(serverPrc.pid()),
                 port.get(),
                 "true"
             );
--- a/test/sun/management/jmxremote/startstop/JMXStartStopTest.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/sun/management/jmxremote/startstop/JMXStartStopTest.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -346,7 +346,7 @@
                         throw new BindException("Starting process failed due to " +
                                                 "the requested port not being available");
                     }
-                    pid = p.getPid();
+                    pid = p.pid();
                 } catch (TimeoutException e) {
                     if (p != null) {
                         p.destroy();
--- a/test/sun/tools/jps/LingeredApp.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/sun/tools/jps/LingeredApp.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -141,7 +141,7 @@
         if (appProcess == null) {
             throw new RuntimeException("Process is not alive");
         }
-        return appProcess.getPid();
+        return appProcess.pid();
     }
 
     /**
--- a/test/sun/tools/jstat/JStatInterval.java	Thu Apr 13 16:01:13 2017 +0000
+++ b/test/sun/tools/jstat/JStatInterval.java	Thu Apr 13 16:27:18 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -36,11 +36,8 @@
 import jdk.testlibrary.ProcessTools;
 import jdk.testlibrary.JDKToolLauncher;
 
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
 
 public class JStatInterval {
     private static final String READY = "READY";
@@ -88,7 +85,7 @@
             throw new Error("Unable to start the monitored application.");
         }
 
-        String pidStr = String.valueOf(app.getPid());
+        String pidStr = String.valueOf(app.pid());
         JDKToolLauncher l = JDKToolLauncher.createUsingTestJDK("jstat");
         l.addToolArg("-compiler");
         l.addToolArg(pidStr);