Merge jdk-9+129
authorduke
Wed, 05 Jul 2017 22:00:06 +0200
changeset 39814 e8373543a3f0
parent 39813 51ebc7e80aee (diff)
parent 39679 f078db83ea53 (current diff)
child 39815 9935748ca894
child 39816 59b3c6267a16
child 39817 2689bb7db9fc
child 39821 af79a51e7d04
child 39823 348e02f4166a
child 39824 629cd556bb2e
child 39896 78f922bcd6cf
child 39898 dbc14ddc6163
child 39899 b3d60e304c3e
child 39903 3b566e86614c
child 39904 113a518e3266
child 39911 86902ef5ff79
child 39913 6993e9e5f2a0
child 39914 cebd92646695
child 39944 8688bada2551
child 39996 330c9163d604
child 40005 3c61d67bcfa4
child 40191 5a91f84138ed
Merge
--- a/.hgtags-top-repo	Wed Jul 05 21:58:30 2017 +0200
+++ b/.hgtags-top-repo	Wed Jul 05 22:00:06 2017 +0200
@@ -370,3 +370,4 @@
 9aa7d40f3a453f51e47f4c1b19eff5740a74a9f8 jdk-9+125
 3a58466296d36944454756ef01e7513ac5e14a16 jdk-9+126
 8fa686245bd2a072ece3392743460030f0854520 jdk-9+127
+b30ae794d974d7dd3eb4e84203f70021823fa6c6 jdk-9+128
--- a/common/autoconf/boot-jdk.m4	Wed Jul 05 21:58:30 2017 +0200
+++ b/common/autoconf/boot-jdk.m4	Wed Jul 05 22:00:06 2017 +0200
@@ -345,6 +345,9 @@
   # Disable special log output when a debug build is used as Boot JDK...
   ADD_JVM_ARG_IF_OK([-XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput],boot_jdk_jvmargs,[$JAVA])
 
+  # Force en-US environment
+  ADD_JVM_ARG_IF_OK([-Duser.language=en -Duser.country=US],boot_jdk_jvmargs,[$JAVA])
+
   # Apply user provided options.
   ADD_JVM_ARG_IF_OK([$with_boot_jdk_jvmargs],boot_jdk_jvmargs,[$JAVA])
 
--- a/common/autoconf/generated-configure.sh	Wed Jul 05 21:58:30 2017 +0200
+++ b/common/autoconf/generated-configure.sh	Wed Jul 05 22:00:06 2017 +0200
@@ -5094,7 +5094,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1467960715
+DATE_WHEN_GENERATED=1469202305
 
 ###############################################################################
 #
@@ -65048,6 +65048,23 @@
   fi
 
 
+  # Force en-US environment
+
+  $ECHO "Check if jvm arg is ok: -Duser.language=en -Duser.country=US" >&5
+  $ECHO "Command: $JAVA -Duser.language=en -Duser.country=US -version" >&5
+  OUTPUT=`$JAVA -Duser.language=en -Duser.country=US -version 2>&1`
+  FOUND_WARN=`$ECHO "$OUTPUT" | $GREP -i warn`
+  FOUND_VERSION=`$ECHO $OUTPUT | $GREP " version \""`
+  if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+    boot_jdk_jvmargs="$boot_jdk_jvmargs -Duser.language=en -Duser.country=US"
+    JVM_ARG_OK=true
+  else
+    $ECHO "Arg failed:" >&5
+    $ECHO "$OUTPUT" >&5
+    JVM_ARG_OK=false
+  fi
+
+
   # Apply user provided options.
 
   $ECHO "Check if jvm arg is ok: $with_boot_jdk_jvmargs" >&5
--- a/corba/.hgtags	Wed Jul 05 21:58:30 2017 +0200
+++ b/corba/.hgtags	Wed Jul 05 22:00:06 2017 +0200
@@ -370,3 +370,4 @@
 1d48e67d1b91eb9f72e49e69a4021edb85e357fc jdk-9+125
 c7f5ba08fcd4b8416e62c21229f9a07c95498919 jdk-9+126
 8fab452b6f4710762ba1d8e55fd62db00b1355fe jdk-9+127
+1f093d3f8cd99cd37c3b0af4cf5c3bffaa9c8b98 jdk-9+128
--- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/activation/ORBD.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/activation/ORBD.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,4 @@
 /*
- *
  * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -22,7 +21,6 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
- *
  */
 
 package com.sun.corba.se.impl.activation;
--- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java	Wed Jul 05 22:00:06 2017 +0200
@@ -34,21 +34,13 @@
 import java.security.Policy;
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-import java.util.Map.Entry;
-import java.util.Collection;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Enumeration;
-import java.util.Properties;
-import java.util.IdentityHashMap;
 import java.util.StringTokenizer;
 import java.util.NoSuchElementException;
 
@@ -165,8 +157,18 @@
      * Return default ValueHandler
      */
     public static ValueHandler createValueHandler() {
+        ValueHandler vh;
+        try {
+            vh = AccessController.doPrivileged(new PrivilegedExceptionAction<ValueHandler>() {
+                public ValueHandler run() throws Exception {
         return Util.createValueHandler();
     }
+            });
+        } catch (PrivilegedActionException e) {
+            throw new InternalError(e.getCause());
+        }
+        return vh;
+    }
 
     /**
      * Returns true if it was accurately determined that the remote ORB is
@@ -664,7 +666,16 @@
      * ValueHandler.
      */
     public static byte getMaxStreamFormatVersion() {
-        ValueHandler vh = Util.createValueHandler();
+        ValueHandler vh;
+        try {
+            vh = AccessController.doPrivileged(new PrivilegedExceptionAction<ValueHandler>() {
+                public ValueHandler run() throws Exception {
+                    return Util.createValueHandler();
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw new InternalError(e.getCause());
+        }
 
         if (!(vh instanceof javax.rmi.CORBA.ValueHandlerMultiFormat))
             return ORBConstants.STREAM_FORMAT_VERSION_1;
--- a/corba/src/java.corba/share/classes/javax/rmi/CORBA/Util.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/corba/src/java.corba/share/classes/javax/rmi/CORBA/Util.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,7 @@
 import java.rmi.Remote;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.SerializablePermission;
 import java.net.MalformedURLException ;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -195,6 +196,8 @@
      */
     public static ValueHandler createValueHandler() {
 
+        isCustomSerializationPermitted();
+
         if (utilDelegate != null) {
             return utilDelegate.createValueHandler();
         }
@@ -337,6 +340,7 @@
     // security reasons. If you know a better solution how to share this code
     // then remove it from PortableRemoteObject. Also in Stub.java
     private static Object createDelegate(String classKey) {
+
         String className = (String)
             AccessController.doPrivileged(new GetPropertyAction(classKey));
         if (className == null) {
@@ -345,7 +349,6 @@
                 className = props.getProperty(classKey);
             }
         }
-
         if (className == null) {
             return new com.sun.corba.se.impl.javax.rmi.CORBA.Util();
         }
@@ -389,4 +392,14 @@
             new GetORBPropertiesFileAction());
     }
 
+    private static void isCustomSerializationPermitted() {
+        SecurityManager sm = System.getSecurityManager();
+        if ( sm != null) {
+            // check that a serialization permission has been
+            // set to allow the loading of the Util delegate
+            // which provides access to custom ValueHandler
+            sm.checkPermission(new SerializablePermission(
+                    "enableCustomValueHandler"));
 }
+    }
+}
--- a/hotspot/.hgtags	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/.hgtags	Wed Jul 05 22:00:06 2017 +0200
@@ -530,3 +530,4 @@
 bb640b49741af3f57f9994129934c46fc173219f jdk-9+125
 adc8c84b7cf8c540d920182f78a2bc982366432a jdk-9+126
 352357128f602dcf0426b1cbe011a4685a4d9f97 jdk-9+127
+22bf6db9767b1b3a1994cbf32eb3331f31ae2093 jdk-9+128
--- a/hotspot/make/test/JtregNative.gmk	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/make/test/JtregNative.gmk	Wed Jul 05 22:00:06 2017 +0200
@@ -51,6 +51,7 @@
     $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \
     $(HOTSPOT_TOPDIR)/test/compiler/calls \
     $(HOTSPOT_TOPDIR)/test/compiler/native \
+    $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
     $(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \
     #
 
@@ -64,6 +65,7 @@
 ifeq ($(TOOLCHAIN_TYPE), solstudio)
     BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_liboverflow := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libSimpleClassFileLoadHook := -lc
+    BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libGetNamedModuleTest := -lc
 endif
 
 BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native
--- a/hotspot/src/os/linux/vm/os_linux.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/os/linux/vm/os_linux.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1742,11 +1742,11 @@
   }
 
   typedef struct {
-    Elf32_Half  code;         // Actual value as defined in elf.h
-    Elf32_Half  compat_class; // Compatibility of archs at VM's sense
-    char        elf_class;    // 32 or 64 bit
-    char        endianess;    // MSB or LSB
-    char*       name;         // String representation
+    Elf32_Half    code;         // Actual value as defined in elf.h
+    Elf32_Half    compat_class; // Compatibility of archs at VM's sense
+    unsigned char elf_class;    // 32 or 64 bit
+    unsigned char endianess;    // MSB or LSB
+    char*         name;         // String representation
   } arch_t;
 
 #ifndef EM_486
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1320,36 +1320,8 @@
 }
 
 bool os::supports_vtime() { return true; }
-
-bool os::enable_vtime() {
-  int fd = ::open("/proc/self/ctl", O_WRONLY);
-  if (fd == -1) {
-    return false;
-  }
-
-  long cmd[] = { PCSET, PR_MSACCT };
-  int res = ::write(fd, cmd, sizeof(long) * 2);
-  ::close(fd);
-  if (res != sizeof(long) * 2) {
-    return false;
-  }
-  return true;
-}
-
-bool os::vtime_enabled() {
-  int fd = ::open("/proc/self/status", O_RDONLY);
-  if (fd == -1) {
-    return false;
-  }
-
-  pstatus_t status;
-  int res = os::read(fd, (void*) &status, sizeof(pstatus_t));
-  ::close(fd);
-  if (res != sizeof(pstatus_t)) {
-    return false;
-  }
-  return status.pr_flags & PR_MSACCT;
-}
+bool os::enable_vtime() { return false; }
+bool os::vtime_enabled() { return false; }
 
 double os::elapsedVTime() {
   return (double)gethrvtime() / (double)hrtime_hz;
--- a/hotspot/src/share/vm/classfile/altHashing.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/altHashing.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -224,7 +224,7 @@
 static const jbyte THREE_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82};
 static const jbyte FOUR_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83};
 static const jchar TWO_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382};
-static const jint ONE_INT[] = { 0x83828180};
+static const jint ONE_INT[] = { (jint)0x83828180};
 static const jbyte SIX_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85};
 static const jchar THREE_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8584};
 static const jbyte EIGHT_BYTE[] = {
@@ -235,7 +235,7 @@
   (jchar) 0x8180, (jchar) 0x8382,
   (jchar) 0x8584, (jchar) 0x8786};
 
-static const jint TWO_INT[] = { 0x83828180, 0x87868584};
+static const jint TWO_INT[] = { (jint)0x83828180, (jint)0x87868584};
 
 static const juint MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3;
 
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -142,7 +142,9 @@
 
   f->do_oop(&_class_loader);
   _dependencies.oops_do(f);
-  _handles->oops_do(f);
+  if (_handles != NULL) {
+    _handles->oops_do(f);
+  }
   if (klass_closure != NULL) {
     classes_do(klass_closure);
   }
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -270,6 +270,10 @@
 
   // For reading from/writing to the CDS archive
   void serialize(SerializeClosure* soc);
+
+  uintx base_address() {
+    return (uintx) _base_address;
+  }
 };
 
 ////////////////////////////////////////////////////////////////////////
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -871,12 +871,17 @@
 
 int  java_lang_Class::oop_size(oop java_class) {
   assert(_oop_size_offset != 0, "must be set");
-  return java_class->int_field(_oop_size_offset);
-}
+  int size = java_class->int_field(_oop_size_offset);
+  assert(size > 0, "Oop size must be greater than zero, not %d", size);
+  return size;
+}
+
 void java_lang_Class::set_oop_size(oop java_class, int size) {
   assert(_oop_size_offset != 0, "must be set");
+  assert(size > 0, "Oop size must be greater than zero, not %d", size);
   java_class->int_field_put(_oop_size_offset, size);
 }
+
 int  java_lang_Class::static_oop_field_count(oop java_class) {
   assert(_static_oop_field_count_offset != 0, "must be set");
   return java_class->int_field(_static_oop_field_count_offset);
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -275,7 +275,6 @@
   static int static_oop_field_count(oop java_class);
   static void set_static_oop_field_count(oop java_class, int size);
 
-
   static GrowableArray<Klass*>* fixup_mirror_list() {
     return _fixup_mirror_list;
   }
--- a/hotspot/src/share/vm/classfile/modules.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/modules.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -820,6 +820,28 @@
 }
 
 
+jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) {
+  assert(ModuleEntryTable::javabase_defined(),
+         "Attempt to call get_named_module before java.base is defined");
+  assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()),
+         "Class loader is not a subclass of java.lang.ClassLoader");
+  assert(package_str != NULL, "the package_str should not be NULL");
+
+  if (strlen(package_str) == 0) {
+    return NULL;
+  }
+  TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
+  const PackageEntry* const pkg_entry =
+    get_package_entry_by_name(package_sym, h_loader, THREAD);
+  const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL);
+
+  if (module_entry != NULL && module_entry->module() != NULL && module_entry->is_named()) {
+    return JNIHandles::make_local(THREAD, JNIHandles::resolve(module_entry->module()));
+  }
+  return NULL;
+}
+
+
 // This method is called by JFR and by the above method.
 jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) {
   const PackageEntry* const pkg_entry =
--- a/hotspot/src/share/vm/classfile/modules.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/modules.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -121,6 +121,7 @@
   // IllegalArgumentException is thrown if loader is neither null nor a subtype of
   // java/lang/ClassLoader.
   static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS);
+  static jobject get_named_module(Handle h_loader, const char* package, TRAPS);
 
   // If package is defined by loader, return the
   // java.lang.reflect.Module object for the module in which the package is defined.
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -238,6 +238,29 @@
   }
 }
 
+u4 SymbolTable::encode_shared(Symbol* sym) {
+  assert(DumpSharedSpaces, "called only during dump time");
+  uintx base_address = uintx(MetaspaceShared::shared_rs()->base());
+  uintx offset = uintx(sym) - base_address;
+  assert(offset < 0x7fffffff, "sanity");
+  return u4(offset);
+}
+
+Symbol* SymbolTable::decode_shared(u4 offset) {
+  assert(!DumpSharedSpaces, "called only during runtime");
+  uintx base_address = _shared_table.base_address();
+  Symbol* sym = (Symbol*)(base_address + offset);
+
+#ifndef PRODUCT
+  const char* s = (const char*)sym->bytes();
+  int len = sym->utf8_length();
+  unsigned int hash = hash_symbol(s, len);
+  assert(sym == lookup_shared(s, len, hash), "must be shared symbol");
+#endif
+
+  return sym;
+}
+
 // Pick hashing algorithm.
 unsigned int SymbolTable::hash_symbol(const char* s, int len) {
   return use_alternate_hashcode() ?
--- a/hotspot/src/share/vm/classfile/symbolTable.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/symbolTable.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -253,6 +253,8 @@
 
   // Sharing
   static void serialize(SerializeClosure* soc);
+  static u4 encode_shared(Symbol* sym);
+  static Symbol* decode_shared(u4 offset);
 
   // Rehash the symbol table if it gets out of balance
   static void rehash_table();
--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -78,7 +78,19 @@
                                            TRAPS) {
     return NULL;
   }
+
   static void serialize(SerializeClosure* soc) {}
+
+  // The (non-application) CDS implementation supports only classes in the boot
+  // class loader, which ensures that the verification constraints are the same
+  // during archive creation time and runtime. Thus we can do the constraint checks
+  // entirely during archive creation time.
+  static bool add_verification_constraint(Klass* k, Symbol* name,
+                  Symbol* from_name, bool from_field_is_protected,
+                  bool from_is_array, bool from_is_object) {return false;}
+  static void finalize_verification_constraints() {}
+  static void check_verification_constraints(instanceKlassHandle klass,
+                                              TRAPS) {}
 };
 
 #endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
--- a/hotspot/src/share/vm/classfile/verificationType.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/verificationType.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionaryShared.hpp"
 #include "classfile/verificationType.hpp"
 #include "classfile/verifier.hpp"
 
@@ -41,6 +42,39 @@
   }
 }
 
+bool VerificationType::resolve_and_check_assignability(instanceKlassHandle klass, Symbol* name,
+         Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, TRAPS) {
+  Klass* obj = SystemDictionary::resolve_or_fail(
+      name, Handle(THREAD, klass->class_loader()),
+      Handle(THREAD, klass->protection_domain()), true, CHECK_false);
+  if (log_is_enabled(Debug, class, resolve)) {
+    Verifier::trace_class_resolution(obj, klass());
+  }
+
+  KlassHandle this_class(THREAD, obj);
+
+  if (this_class->is_interface() && (!from_field_is_protected ||
+      from_name != vmSymbols::java_lang_Object())) {
+    // If we are not trying to access a protected field or method in
+    // java.lang.Object then, for arrays, we only allow assignability
+    // to interfaces java.lang.Cloneable and java.io.Serializable.
+    // Otherwise, we treat interfaces as java.lang.Object.
+    return !from_is_array ||
+      this_class == SystemDictionary::Cloneable_klass() ||
+      this_class == SystemDictionary::Serializable_klass();
+  } else if (from_is_object) {
+    Klass* from_class = SystemDictionary::resolve_or_fail(
+        from_name, Handle(THREAD, klass->class_loader()),
+        Handle(THREAD, klass->protection_domain()), true, CHECK_false);
+    if (log_is_enabled(Debug, class, resolve)) {
+      Verifier::trace_class_resolution(from_class, klass());
+    }
+    return InstanceKlass::cast(from_class)->is_subclass_of(this_class());
+  }
+
+  return false;
+}
+
 bool VerificationType::is_reference_assignable_from(
     const VerificationType& from, ClassVerifier* context,
     bool from_field_is_protected, TRAPS) const {
@@ -58,33 +92,17 @@
       // any object or array is assignable to java.lang.Object
       return true;
     }
-    Klass* obj = SystemDictionary::resolve_or_fail(
-        name(), Handle(THREAD, klass->class_loader()),
-        Handle(THREAD, klass->protection_domain()), true, CHECK_false);
-    if (log_is_enabled(Debug, class, resolve)) {
-      Verifier::trace_class_resolution(obj, klass());
+
+    if (DumpSharedSpaces && SystemDictionaryShared::add_verification_constraint(klass(),
+              name(), from.name(), from_field_is_protected, from.is_array(),
+              from.is_object())) {
+      // If add_verification_constraint() returns true, the resolution/check should be
+      // delayed until runtime.
+      return true;
     }
 
-    KlassHandle this_class(THREAD, obj);
-
-    if (this_class->is_interface() && (!from_field_is_protected ||
-        from.name() != vmSymbols::java_lang_Object())) {
-      // If we are not trying to access a protected field or method in
-      // java.lang.Object then, for arrays, we only allow assignability
-      // to interfaces java.lang.Cloneable and java.io.Serializable.
-      // Otherwise, we treat interfaces as java.lang.Object.
-      return !from.is_array() ||
-        this_class == SystemDictionary::Cloneable_klass() ||
-        this_class == SystemDictionary::Serializable_klass();
-    } else if (from.is_object()) {
-      Klass* from_class = SystemDictionary::resolve_or_fail(
-          from.name(), Handle(THREAD, klass->class_loader()),
-          Handle(THREAD, klass->protection_domain()), true, CHECK_false);
-      if (log_is_enabled(Debug, class, resolve)) {
-        Verifier::trace_class_resolution(from_class, klass());
-      }
-      return InstanceKlass::cast(from_class)->is_subclass_of(this_class());
-    }
+    return resolve_and_check_assignability(klass(), name(), from.name(),
+          from_field_is_protected, from.is_array(), from.is_object(), THREAD);
   } else if (is_array() && from.is_array()) {
     VerificationType comp_this = get_component(context, CHECK_false);
     VerificationType comp_from = from.get_component(context, CHECK_false);
--- a/hotspot/src/share/vm/classfile/verificationType.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/verificationType.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -333,6 +333,12 @@
   bool is_reference_assignable_from(
     const VerificationType&, ClassVerifier*, bool from_field_is_protected,
     TRAPS) const;
+
+ public:
+  static bool resolve_and_check_assignability(instanceKlassHandle klass, Symbol* name,
+                                              Symbol* from_name, bool from_field_is_protected,
+                                              bool from_is_array, bool from_is_object,
+                                              TRAPS);
 };
 
 #endif // SHARE_VM_CLASSFILE_VERIFICATIONTYPE_HPP
--- a/hotspot/src/share/vm/classfile/verifier.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/classfile/verifier.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -2377,9 +2377,17 @@
       case Bytecodes::_ifnonnull:
         target = bcs.dest();
         if (visited_branches->contains(bci)) {
-          if (bci_stack->is_empty()) return true;
-          // Pop a bytecode starting offset and scan from there.
-          bcs.set_start(bci_stack->pop());
+          if (bci_stack->is_empty()) {
+            if (handler_stack->is_empty()) {
+              return true;
+            } else {
+              // Parse the catch handlers for try blocks containing athrow.
+              bcs.set_start(handler_stack->pop());
+            }
+          } else {
+            // Pop a bytecode starting offset and scan from there.
+            bcs.set_start(bci_stack->pop());
+          }
         } else {
           if (target > bci) { // forward branch
             if (target >= code_length) return false;
@@ -2402,9 +2410,17 @@
       case Bytecodes::_goto_w:
         target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w());
         if (visited_branches->contains(bci)) {
-          if (bci_stack->is_empty()) return true;
-          // Been here before, pop new starting offset from stack.
-          bcs.set_start(bci_stack->pop());
+          if (bci_stack->is_empty()) {
+            if (handler_stack->is_empty()) {
+              return true;
+            } else {
+              // Parse the catch handlers for try blocks containing athrow.
+              bcs.set_start(handler_stack->pop());
+            }
+          } else {
+            // Been here before, pop new starting offset from stack.
+            bcs.set_start(bci_stack->pop());
+          }
         } else {
           if (target >= code_length) return false;
           // Continue scanning from the target onward.
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1256,9 +1256,7 @@
       // set between the last GC or pause and now. We need to clear the
       // incremental collection set and then start rebuilding it afresh
       // after this full GC.
-      abandon_collection_set(collection_set()->inc_head());
-      collection_set()->clear_incremental();
-      collection_set()->stop_incremental_building();
+      abandon_collection_set(collection_set());
 
       tear_down_region_sets(false /* free_list_only */);
       collector_state()->set_gcs_are_young(true);
@@ -1379,7 +1377,6 @@
       _verifier->check_bitmaps("Full GC End");
 
       // Start a new incremental collection set for the next pause
-      assert(collection_set()->head() == NULL, "must be");
       collection_set()->start_incremental_building();
 
       clear_cset_fast_test();
@@ -1724,8 +1721,6 @@
   _old_marking_cycles_started(0),
   _old_marking_cycles_completed(0),
   _in_cset_fast_test(),
-  _worker_cset_start_region(NULL),
-  _worker_cset_start_region_time_stamp(NULL),
   _gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()),
   _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()) {
 
@@ -1748,8 +1743,6 @@
   uint n_queues = ParallelGCThreads;
   _task_queues = new RefToScanQueueSet(n_queues);
 
-  _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC);
-  _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(uint, n_queues, mtGC);
   _evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC);
 
   for (uint i = 0; i < n_queues; i++) {
@@ -1758,7 +1751,6 @@
     _task_queues->register_queue(i, q);
     ::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo();
   }
-  clear_cset_start_regions();
 
   // Initialize the G1EvacuationFailureALot counters and flags.
   NOT_PRODUCT(reset_evacuation_should_fail();)
@@ -1987,6 +1979,8 @@
 
   _preserved_marks_set.init(ParallelGCThreads);
 
+  _collection_set.initialize(max_regions());
+
   return JNI_OK;
 }
 
@@ -2420,117 +2414,12 @@
   _hrm.par_iterate(cl, worker_id, hrclaimer, concurrent);
 }
 
-// Clear the cached CSet starting regions and (more importantly)
-// the time stamps. Called when we reset the GC time stamp.
-void G1CollectedHeap::clear_cset_start_regions() {
-  assert(_worker_cset_start_region != NULL, "sanity");
-  assert(_worker_cset_start_region_time_stamp != NULL, "sanity");
-
-  for (uint i = 0; i < ParallelGCThreads; i++) {
-    _worker_cset_start_region[i] = NULL;
-    _worker_cset_start_region_time_stamp[i] = 0;
-  }
+void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
+  _collection_set.iterate(cl);
 }
 
-// Given the id of a worker, obtain or calculate a suitable
-// starting region for iterating over the current collection set.
-HeapRegion* G1CollectedHeap::start_cset_region_for_worker(uint worker_i) {
-  assert(get_gc_time_stamp() > 0, "should have been updated by now");
-
-  HeapRegion* result = NULL;
-  unsigned gc_time_stamp = get_gc_time_stamp();
-
-  if (_worker_cset_start_region_time_stamp[worker_i] == gc_time_stamp) {
-    // Cached starting region for current worker was set
-    // during the current pause - so it's valid.
-    // Note: the cached starting heap region may be NULL
-    // (when the collection set is empty).
-    result = _worker_cset_start_region[worker_i];
-    assert(result == NULL || result->in_collection_set(), "sanity");
-    return result;
-  }
-
-  // The cached entry was not valid so let's calculate
-  // a suitable starting heap region for this worker.
-
-  // We want the parallel threads to start their collection
-  // set iteration at different collection set regions to
-  // avoid contention.
-  // If we have:
-  //          n collection set regions
-  //          p threads
-  // Then thread t will start at region floor ((t * n) / p)
-
-  result = collection_set()->head();
-  uint cs_size = collection_set()->region_length();
-  uint active_workers = workers()->active_workers();
-
-  uint end_ind   = (cs_size * worker_i) / active_workers;
-  uint start_ind = 0;
-
-  if (worker_i > 0 &&
-      _worker_cset_start_region_time_stamp[worker_i - 1] == gc_time_stamp) {
-    // Previous workers starting region is valid
-    // so let's iterate from there
-    start_ind = (cs_size * (worker_i - 1)) / active_workers;
-    OrderAccess::loadload();
-    result = _worker_cset_start_region[worker_i - 1];
-  }
-
-  for (uint i = start_ind; i < end_ind; i++) {
-    result = result->next_in_collection_set();
-  }
-
-  // Note: the calculated starting heap region may be NULL
-  // (when the collection set is empty).
-  assert(result == NULL || result->in_collection_set(), "sanity");
-  assert(_worker_cset_start_region_time_stamp[worker_i] != gc_time_stamp,
-         "should be updated only once per pause");
-  _worker_cset_start_region[worker_i] = result;
-  OrderAccess::storestore();
-  _worker_cset_start_region_time_stamp[worker_i] = gc_time_stamp;
-  return result;
-}
-
-void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
-  HeapRegion* r = collection_set()->head();
-  while (r != NULL) {
-    HeapRegion* next = r->next_in_collection_set();
-    if (cl->doHeapRegion(r)) {
-      cl->incomplete();
-      return;
-    }
-    r = next;
-  }
-}
-
-void G1CollectedHeap::collection_set_iterate_from(HeapRegion* r,
-                                                  HeapRegionClosure *cl) {
-  if (r == NULL) {
-    // The CSet is empty so there's nothing to do.
-    return;
-  }
-
-  assert(r->in_collection_set(),
-         "Start region must be a member of the collection set.");
-  HeapRegion* cur = r;
-  while (cur != NULL) {
-    HeapRegion* next = cur->next_in_collection_set();
-    if (cl->doHeapRegion(cur) && false) {
-      cl->incomplete();
-      return;
-    }
-    cur = next;
-  }
-  cur = collection_set()->head();
-  while (cur != r) {
-    HeapRegion* next = cur->next_in_collection_set();
-    if (cl->doHeapRegion(cur) && false) {
-      cl->incomplete();
-      return;
-    }
-    cur = next;
-  }
+void G1CollectedHeap::collection_set_iterate_from(HeapRegionClosure *cl, uint worker_id) {
+  _collection_set.iterate_from(cl, worker_id, workers()->active_workers());
 }
 
 HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const {
@@ -3090,6 +2979,18 @@
   g1_policy()->phase_times()->record_root_region_scan_wait_time(wait_time_ms);
 }
 
+class G1PrintCollectionSetClosure : public HeapRegionClosure {
+private:
+  G1HRPrinter* _hr_printer;
+public:
+  G1PrintCollectionSetClosure(G1HRPrinter* hr_printer) : HeapRegionClosure(), _hr_printer(hr_printer) { }
+
+  virtual bool doHeapRegion(HeapRegion* r) {
+    _hr_printer->cset(r);
+    return false;
+  }
+};
+
 bool
 G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
   assert_at_safepoint(true /* should_be_vm_thread */);
@@ -3268,11 +3169,8 @@
         _cm->verify_no_cset_oops();
 
         if (_hr_printer.is_active()) {
-          HeapRegion* hr = collection_set()->head();
-          while (hr != NULL) {
-            _hr_printer.cset(hr);
-            hr = hr->next_in_collection_set();
-          }
+          G1PrintCollectionSetClosure cl(&_hr_printer);
+          _collection_set.iterate(&cl);
         }
 
         // Initialize the GC alloc regions.
@@ -3287,12 +3185,10 @@
         post_evacuate_collection_set(evacuation_info, &per_thread_states);
 
         const size_t* surviving_young_words = per_thread_states.surviving_young_words();
-        free_collection_set(collection_set()->head(), evacuation_info, surviving_young_words);
+        free_collection_set(&_collection_set, evacuation_info, surviving_young_words);
 
         eagerly_reclaim_humongous_regions();
 
-        collection_set()->clear_head();
-
         record_obj_copy_mem_stats();
         _survivor_evac_stats.adjust_desired_plab_sz();
         _old_evac_stats.adjust_desired_plab_sz();
@@ -4704,120 +4600,139 @@
   workers()->run_task(&g1_par_scrub_rs_task);
 }
 
-void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info, const size_t* surviving_young_words) {
-  size_t pre_used = 0;
-  FreeRegionList local_free_list("Local List for CSet Freeing");
-
-  double young_time_ms     = 0.0;
-  double non_young_time_ms = 0.0;
-
-  _eden.clear();
-
-  G1Policy* policy = g1_policy();
-
-  double start_sec = os::elapsedTime();
-  bool non_young = true;
-
-  HeapRegion* cur = cs_head;
-  int age_bound = -1;
-  size_t rs_lengths = 0;
-
-  while (cur != NULL) {
-    assert(!is_on_master_free_list(cur), "sanity");
-    if (non_young) {
-      if (cur->is_young()) {
-        double end_sec = os::elapsedTime();
-        double elapsed_ms = (end_sec - start_sec) * 1000.0;
-        non_young_time_ms += elapsed_ms;
-
-        start_sec = os::elapsedTime();
-        non_young = false;
-      }
+class G1FreeCollectionSetClosure : public HeapRegionClosure {
+private:
+  const size_t* _surviving_young_words;
+
+  FreeRegionList _local_free_list;
+  size_t _rs_lengths;
+  // Bytes used in successfully evacuated regions before the evacuation.
+  size_t _before_used_bytes;
+  // Bytes used in unsucessfully evacuated regions before the evacuation
+  size_t _after_used_bytes;
+
+  size_t _bytes_allocated_in_old_since_last_gc;
+
+  size_t _failure_used_words;
+  size_t _failure_waste_words;
+
+  double _young_time;
+  double _non_young_time;
+public:
+  G1FreeCollectionSetClosure(const size_t* surviving_young_words) :
+    HeapRegionClosure(),
+    _surviving_young_words(surviving_young_words),
+    _local_free_list("Local Region List for CSet Freeing"),
+    _rs_lengths(0),
+    _before_used_bytes(0),
+    _after_used_bytes(0),
+    _bytes_allocated_in_old_since_last_gc(0),
+    _failure_used_words(0),
+    _failure_waste_words(0),
+    _young_time(0.0),
+    _non_young_time(0.0) {
+  }
+
+  virtual bool doHeapRegion(HeapRegion* r) {
+    double start_time = os::elapsedTime();
+
+    bool is_young = r->is_young();
+
+    G1CollectedHeap* g1h = G1CollectedHeap::heap();
+    assert(!g1h->is_on_master_free_list(r), "sanity");
+
+    _rs_lengths += r->rem_set()->occupied_locked();
+
+    assert(r->in_collection_set(), "Region %u should be in collection set.", r->hrm_index());
+    g1h->clear_in_cset(r);
+
+    if (is_young) {
+      int index = r->young_index_in_cset();
+      assert(index != -1, "Young index in collection set must not be -1 for region %u", r->hrm_index());
+      assert((uint) index < g1h->collection_set()->young_region_length(), "invariant");
+      size_t words_survived = _surviving_young_words[index];
+      r->record_surv_words_in_group(words_survived);
     } else {
-      if (!cur->is_young()) {
-        double end_sec = os::elapsedTime();
-        double elapsed_ms = (end_sec - start_sec) * 1000.0;
-        young_time_ms += elapsed_ms;
-
-        start_sec = os::elapsedTime();
-        non_young = true;
-      }
+      assert(r->young_index_in_cset() == -1, "Young index for old region %u in collection set must be -1", r->hrm_index());
     }
 
-    rs_lengths += cur->rem_set()->occupied_locked();
-
-    HeapRegion* next = cur->next_in_collection_set();
-    assert(cur->in_collection_set(), "bad CS");
-    cur->set_next_in_collection_set(NULL);
-    clear_in_cset(cur);
-
-    if (cur->is_young()) {
-      int index = cur->young_index_in_cset();
-      assert(index != -1, "invariant");
-      assert((uint) index < collection_set()->young_region_length(), "invariant");
-      size_t words_survived = surviving_young_words[index];
-      cur->record_surv_words_in_group(words_survived);
-
+    if (!r->evacuation_failed()) {
+      assert(r->not_empty(), "Region %u is an empty region in the collection set.", r->hrm_index());
+      _before_used_bytes += r->used();
+      g1h->free_region(r, &_local_free_list, false /* par */, true /* locked */);
     } else {
-      int index = cur->young_index_in_cset();
-      assert(index == -1, "invariant");
-    }
-
-    assert( (cur->is_young() && cur->young_index_in_cset() > -1) ||
-            (!cur->is_young() && cur->young_index_in_cset() == -1),
-            "invariant" );
-
-    if (!cur->evacuation_failed()) {
-      MemRegion used_mr = cur->used_region();
-
-      // And the region is empty.
-      assert(!used_mr.is_empty(), "Should not have empty regions in a CS.");
-      pre_used += cur->used();
-      free_region(cur, &local_free_list, false /* par */, true /* locked */);
-    } else {
-      cur->uninstall_surv_rate_group();
-      if (cur->is_young()) {
-        cur->set_young_index_in_cset(-1);
-      }
-      cur->set_evacuation_failed(false);
+      r->uninstall_surv_rate_group();
+      r->set_young_index_in_cset(-1);
+      r->set_evacuation_failed(false);
       // When moving a young gen region to old gen, we "allocate" that whole region
       // there. This is in addition to any already evacuated objects. Notify the
       // policy about that.
       // Old gen regions do not cause an additional allocation: both the objects
       // still in the region and the ones already moved are accounted for elsewhere.
-      if (cur->is_young()) {
-        policy->add_bytes_allocated_in_old_since_last_gc(HeapRegion::GrainBytes);
+      if (is_young) {
+        _bytes_allocated_in_old_since_last_gc += HeapRegion::GrainBytes;
       }
       // The region is now considered to be old.
-      cur->set_old();
+      r->set_old();
       // Do some allocation statistics accounting. Regions that failed evacuation
       // are always made old, so there is no need to update anything in the young
       // gen statistics, but we need to update old gen statistics.
-      size_t used_words = cur->marked_bytes() / HeapWordSize;
-      _old_evac_stats.add_failure_used_and_waste(used_words, HeapRegion::GrainWords - used_words);
-      _old_set.add(cur);
-      evacuation_info.increment_collectionset_used_after(cur->used());
+      size_t used_words = r->marked_bytes() / HeapWordSize;
+
+      _failure_used_words += used_words;
+      _failure_waste_words += HeapRegion::GrainWords - used_words;
+
+      g1h->old_set_add(r);
+      _after_used_bytes += r->used();
+    }
+
+    if (is_young) {
+      _young_time += os::elapsedTime() - start_time;
+    } else {
+      _non_young_time += os::elapsedTime() - start_time;
     }
-    cur = next;
+    return false;
   }
 
-  evacuation_info.set_regions_freed(local_free_list.length());
-  policy->record_max_rs_lengths(rs_lengths);
+  FreeRegionList* local_free_list() { return &_local_free_list; }
+  size_t rs_lengths() const { return _rs_lengths; }
+  size_t before_used_bytes() const { return _before_used_bytes; }
+  size_t after_used_bytes() const { return _after_used_bytes; }
+
+  size_t bytes_allocated_in_old_since_last_gc() const { return _bytes_allocated_in_old_since_last_gc; }
+
+  size_t failure_used_words() const { return _failure_used_words; }
+  size_t failure_waste_words() const { return _failure_waste_words; }
+
+  double young_time() const { return _young_time; }
+  double non_young_time() const { return _non_young_time; }
+};
+
+void G1CollectedHeap::free_collection_set(G1CollectionSet* collection_set, EvacuationInfo& evacuation_info, const size_t* surviving_young_words) {
+  _eden.clear();
+
+  G1FreeCollectionSetClosure cl(surviving_young_words);
+  collection_set_iterate(&cl);
+
+  evacuation_info.set_regions_freed(cl.local_free_list()->length());
+  evacuation_info.increment_collectionset_used_after(cl.after_used_bytes());
+
+  G1Policy* policy = g1_policy();
+
+  policy->record_max_rs_lengths(cl.rs_lengths());
   policy->cset_regions_freed();
 
-  double end_sec = os::elapsedTime();
-  double elapsed_ms = (end_sec - start_sec) * 1000.0;
-
-  if (non_young) {
-    non_young_time_ms += elapsed_ms;
-  } else {
-    young_time_ms += elapsed_ms;
-  }
-
-  prepend_to_freelist(&local_free_list);
-  decrement_summary_bytes(pre_used);
-  policy->phase_times()->record_young_free_cset_time_ms(young_time_ms);
-  policy->phase_times()->record_non_young_free_cset_time_ms(non_young_time_ms);
+  prepend_to_freelist(cl.local_free_list());
+  decrement_summary_bytes(cl.before_used_bytes());
+
+  policy->add_bytes_allocated_in_old_since_last_gc(cl.bytes_allocated_in_old_since_last_gc());
+
+  _old_evac_stats.add_failure_used_and_waste(cl.failure_used_words(), cl.failure_waste_words());
+
+  policy->phase_times()->record_young_free_cset_time_ms(cl.young_time() * 1000.0);
+  policy->phase_times()->record_non_young_free_cset_time_ms(cl.non_young_time() * 1000.0);
+
+  collection_set->clear();
 }
 
 class G1FreeHumongousRegionClosure : public HeapRegionClosure {
@@ -4960,25 +4875,22 @@
                                                                     cl.humongous_free_count());
 }
 
-// This routine is similar to the above but does not record
-// any policy statistics or update free lists; we are abandoning
-// the current incremental collection set in preparation of a
-// full collection. After the full GC we will start to build up
-// the incremental collection set again.
-// This is only called when we're doing a full collection
-// and is immediately followed by the tearing down of the young list.
-
-void G1CollectedHeap::abandon_collection_set(HeapRegion* cs_head) {
-  HeapRegion* cur = cs_head;
-
-  while (cur != NULL) {
-    HeapRegion* next = cur->next_in_collection_set();
-    assert(cur->in_collection_set(), "bad CS");
-    cur->set_next_in_collection_set(NULL);
-    clear_in_cset(cur);
-    cur->set_young_index_in_cset(-1);
-    cur = next;
+class G1AbandonCollectionSetClosure : public HeapRegionClosure {
+public:
+  virtual bool doHeapRegion(HeapRegion* r) {
+    assert(r->in_collection_set(), "Region %u must have been in collection set", r->hrm_index());
+    G1CollectedHeap::heap()->clear_in_cset(r);
+    r->set_young_index_in_cset(-1);
+    return false;
   }
+};
+
+void G1CollectedHeap::abandon_collection_set(G1CollectionSet* collection_set) {
+  G1AbandonCollectionSetClosure cl;
+  collection_set->iterate(&cl);
+
+  collection_set->clear();
+  collection_set->stop_incremental_building();
 }
 
 void G1CollectedHeap::set_free_regions_coming() {
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -778,13 +778,13 @@
   // The closure used to refine a single card.
   RefineCardTableEntryClosure* _refine_cte_cl;
 
-  // After a collection pause, make the regions in the CS into free
+  // After a collection pause, convert the regions in the collection set into free
   // regions.
-  void free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info, const size_t* surviving_young_words);
+  void free_collection_set(G1CollectionSet* collection_set, EvacuationInfo& evacuation_info, const size_t* surviving_young_words);
 
   // Abandon the current collection set without recording policy
   // statistics or updating free lists.
-  void abandon_collection_set(HeapRegion* cs_head);
+  void abandon_collection_set(G1CollectionSet* collection_set);
 
   // The concurrent marker (and the thread it runs in.)
   G1ConcurrentMark* _cm;
@@ -930,16 +930,6 @@
   // discovery.
   G1CMIsAliveClosure _is_alive_closure_cm;
 
-  // Cache used by G1CollectedHeap::start_cset_region_for_worker().
-  HeapRegion** _worker_cset_start_region;
-
-  // Time stamp to validate the regions recorded in the cache
-  // used by G1CollectedHeap::start_cset_region_for_worker().
-  // The heap region entry for a given worker is valid iff
-  // the associated time stamp value matches the current value
-  // of G1CollectedHeap::_gc_time_stamp.
-  uint* _worker_cset_start_region_time_stamp;
-
   volatile bool _free_regions_coming;
 
 public:
@@ -1211,19 +1201,14 @@
                                HeapRegionClaimer* hrclaimer,
                                bool concurrent = false) const;
 
-  // Clear the cached cset start regions and (more importantly)
-  // the time stamps. Called when we reset the GC time stamp.
-  void clear_cset_start_regions();
-
-  // Given the id of a worker, obtain or calculate a suitable
-  // starting region for iterating over the current collection set.
-  HeapRegion* start_cset_region_for_worker(uint worker_i);
-
   // Iterate over the regions (if any) in the current collection set.
   void collection_set_iterate(HeapRegionClosure* blk);
 
-  // As above but starting from region r
-  void collection_set_iterate_from(HeapRegion* r, HeapRegionClosure *blk);
+  // Iterate over the regions (if any) in the current collection set. Starts the
+  // iteration over the entire collection set so that the start regions of a given
+  // worker id over the set active_workers are evenly spread across the set of
+  // collection set regions.
+  void collection_set_iterate_from(HeapRegionClosure *blk, uint worker_id);
 
   HeapRegion* next_compaction_region(const HeapRegion* from) const;
 
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -89,16 +89,13 @@
 }
 
 inline void G1CollectedHeap::reset_gc_time_stamp() {
+  assert_at_safepoint(true);
   _gc_time_stamp = 0;
-  OrderAccess::fence();
-  // Clear the cached CSet starting regions and time stamps.
-  // Their validity is dependent on the GC timestamp.
-  clear_cset_start_regions();
 }
 
 inline void G1CollectedHeap::increment_gc_time_stamp() {
+  assert_at_safepoint(true);
   ++_gc_time_stamp;
-  OrderAccess::fence();
 }
 
 inline void G1CollectedHeap::old_set_add(HeapRegion* hr) {
--- a/hotspot/src/share/vm/gc/g1/g1CollectionSet.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectionSet.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -30,6 +30,7 @@
 #include "gc/g1/heapRegion.inline.hpp"
 #include "gc/g1/heapRegionRemSet.hpp"
 #include "gc/g1/heapRegionSet.hpp"
+#include "logging/logStream.hpp"
 #include "utilities/debug.hpp"
 
 G1CollectorState* G1CollectionSet::collector_state() {
@@ -55,48 +56,63 @@
   _eden_region_length(0),
   _survivor_region_length(0),
   _old_region_length(0),
-
-  _head(NULL),
   _bytes_used_before(0),
   _recorded_rs_lengths(0),
+  _collection_set_regions(NULL),
+  _collection_set_cur_length(0),
+  _collection_set_max_length(0),
   // Incremental CSet attributes
   _inc_build_state(Inactive),
-  _inc_head(NULL),
-  _inc_tail(NULL),
   _inc_bytes_used_before(0),
   _inc_recorded_rs_lengths(0),
   _inc_recorded_rs_lengths_diffs(0),
   _inc_predicted_elapsed_time_ms(0.0),
-  _inc_predicted_elapsed_time_ms_diffs(0.0),
-  _inc_region_length(0) {}
+  _inc_predicted_elapsed_time_ms_diffs(0.0) {
+}
 
 G1CollectionSet::~G1CollectionSet() {
+  if (_collection_set_regions != NULL) {
+    FREE_C_HEAP_ARRAY(uint, _collection_set_regions);
+  }
   delete _cset_chooser;
 }
 
 void G1CollectionSet::init_region_lengths(uint eden_cset_region_length,
                                           uint survivor_cset_region_length) {
+  assert_at_safepoint(true);
+
   _eden_region_length     = eden_cset_region_length;
   _survivor_region_length = survivor_cset_region_length;
 
-  assert(young_region_length() == _inc_region_length, "should match %u == %u", young_region_length(), _inc_region_length);
+  assert((size_t) young_region_length() == _collection_set_cur_length,
+         "Young region length %u should match collection set length " SIZE_FORMAT, young_region_length(), _collection_set_cur_length);
 
   _old_region_length      = 0;
 }
 
+void G1CollectionSet::initialize(uint max_region_length) {
+  guarantee(_collection_set_regions == NULL, "Must only initialize once.");
+  _collection_set_max_length = max_region_length;
+  _collection_set_regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC);
+}
+
 void G1CollectionSet::set_recorded_rs_lengths(size_t rs_lengths) {
   _recorded_rs_lengths = rs_lengths;
 }
 
 // Add the heap region at the head of the non-incremental collection set
 void G1CollectionSet::add_old_region(HeapRegion* hr) {
+  assert_at_safepoint(true);
+
   assert(_inc_build_state == Active, "Precondition");
   assert(hr->is_old(), "the region should be old");
 
   assert(!hr->in_collection_set(), "should not already be in the CSet");
   _g1->register_old_region_with_cset(hr);
-  hr->set_next_in_collection_set(_head);
-  _head = hr;
+
+  _collection_set_regions[_collection_set_cur_length++] = hr->hrm_index();
+  assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set now larger than maximum size.");
+
   _bytes_used_before += hr->used();
   size_t rs_length = hr->rem_set()->occupied();
   _recorded_rs_lengths += rs_length;
@@ -105,12 +121,10 @@
 
 // Initialize the per-collection-set information
 void G1CollectionSet::start_incremental_building() {
+  assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set.");
   assert(_inc_build_state == Inactive, "Precondition");
 
-  _inc_head = NULL;
-  _inc_tail = NULL;
   _inc_bytes_used_before = 0;
-  _inc_region_length = 0;
 
   _inc_recorded_rs_lengths = 0;
   _inc_recorded_rs_lengths_diffs = 0;
@@ -151,6 +165,38 @@
   _inc_predicted_elapsed_time_ms_diffs = 0.0;
 }
 
+void G1CollectionSet::clear() {
+  assert_at_safepoint(true);
+  _collection_set_cur_length = 0;
+}
+
+void G1CollectionSet::iterate(HeapRegionClosure* cl) const {
+  iterate_from(cl, 0, 1);
+}
+
+void G1CollectionSet::iterate_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const {
+  size_t len = _collection_set_cur_length;
+  OrderAccess::loadload();
+  if (len == 0) {
+    return;
+  }
+  size_t start_pos = (worker_id * len) / total_workers;
+  size_t cur_pos = start_pos;
+
+  do {
+    HeapRegion* r = G1CollectedHeap::heap()->region_at(_collection_set_regions[cur_pos]);
+    bool result = cl->doHeapRegion(r);
+    if (result) {
+      cl->incomplete();
+      return;
+    }
+    cur_pos++;
+    if (cur_pos == len) {
+      cur_pos = 0;
+    }
+  } while (cur_pos != start_pos);
+}
+
 void G1CollectionSet::update_young_region_prediction(HeapRegion* hr,
                                                      size_t new_rs_length) {
   // Update the CSet information that is dependent on the new RS length
@@ -183,8 +229,16 @@
   assert(hr->is_young(), "invariant");
   assert(_inc_build_state == Active, "Precondition");
 
-  hr->set_young_index_in_cset(_inc_region_length);
-  _inc_region_length++;
+  size_t collection_set_length = _collection_set_cur_length;
+  assert(collection_set_length <= INT_MAX, "Collection set is too large with %d entries", (int)collection_set_length);
+  hr->set_young_index_in_cset((int)collection_set_length);
+
+  _collection_set_regions[collection_set_length] = hr->hrm_index();
+  // Concurrent readers must observe the store of the value in the array before an
+  // update to the length field.
+  OrderAccess::storestore();
+  _collection_set_cur_length++;
+  assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set larger than maximum allowed.");
 
   // This routine is used when:
   // * adding survivor regions to the incremental cset at the end of an
@@ -218,59 +272,81 @@
 
   assert(!hr->in_collection_set(), "invariant");
   _g1->register_young_region_with_cset(hr);
-  assert(hr->next_in_collection_set() == NULL, "invariant");
 }
 
-// Add the region at the RHS of the incremental cset
 void G1CollectionSet::add_survivor_regions(HeapRegion* hr) {
-  // We should only ever be appending survivors at the end of a pause
-  assert(hr->is_survivor(), "Logic");
-
-  // Do the 'common' stuff
+  assert(hr->is_survivor(), "Must only add survivor regions, but is %s", hr->get_type_str());
   add_young_region_common(hr);
-
-  // Now add the region at the right hand side
-  if (_inc_tail == NULL) {
-    assert(_inc_head == NULL, "invariant");
-    _inc_head = hr;
-  } else {
-    _inc_tail->set_next_in_collection_set(hr);
-  }
-  _inc_tail = hr;
 }
 
-// Add the region to the LHS of the incremental cset
 void G1CollectionSet::add_eden_region(HeapRegion* hr) {
-  // Survivors should be added to the RHS at the end of a pause
-  assert(hr->is_eden(), "Logic");
-
-  // Do the 'common' stuff
+  assert(hr->is_eden(), "Must only add eden regions, but is %s", hr->get_type_str());
   add_young_region_common(hr);
-
-  // Add the region at the left hand side
-  hr->set_next_in_collection_set(_inc_head);
-  if (_inc_head == NULL) {
-    assert(_inc_tail == NULL, "Invariant");
-    _inc_tail = hr;
-  }
-  _inc_head = hr;
 }
 
 #ifndef PRODUCT
-void G1CollectionSet::print(HeapRegion* list_head, outputStream* st) {
-  assert(list_head == inc_head() || list_head == head(), "must be");
+class G1VerifyYoungAgesClosure : public HeapRegionClosure {
+public:
+  bool _valid;
+public:
+  G1VerifyYoungAgesClosure() : HeapRegionClosure(), _valid(true) { }
+
+  virtual bool doHeapRegion(HeapRegion* r) {
+    guarantee(r->is_young(), "Region must be young but is %s", r->get_type_str());
+
+    SurvRateGroup* group = r->surv_rate_group();
+
+    if (group == NULL) {
+      log_error(gc, verify)("## encountered NULL surv_rate_group in young region");
+      _valid = false;
+    }
+
+    if (r->age_in_surv_rate_group() < 0) {
+      log_error(gc, verify)("## encountered negative age in young region");
+      _valid = false;
+    }
+
+    return false;
+  }
+
+  bool valid() const { return _valid; }
+};
 
+bool G1CollectionSet::verify_young_ages() {
+  assert_at_safepoint(true);
+
+  G1VerifyYoungAgesClosure cl;
+  iterate(&cl);
+
+  if (!cl.valid()) {
+    LogStreamHandle(Error, gc, verify) log;
+    print(&log);
+  }
+
+  return cl.valid();
+}
+
+class G1PrintCollectionSetClosure : public HeapRegionClosure {
+  outputStream* _st;
+public:
+  G1PrintCollectionSetClosure(outputStream* st) : HeapRegionClosure(), _st(st) { }
+
+  virtual bool doHeapRegion(HeapRegion* r) {
+    assert(r->in_collection_set(), "Region %u should be in collection set", r->hrm_index());
+    _st->print_cr("  " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d",
+                  HR_FORMAT_PARAMS(r),
+                  p2i(r->prev_top_at_mark_start()),
+                  p2i(r->next_top_at_mark_start()),
+                  r->age_in_surv_rate_group_cond());
+    return false;
+  }
+};
+
+void G1CollectionSet::print(outputStream* st) {
   st->print_cr("\nCollection_set:");
-  HeapRegion* csr = list_head;
-  while (csr != NULL) {
-    HeapRegion* next = csr->next_in_collection_set();
-    assert(csr->in_collection_set(), "bad CS");
-    st->print_cr("  " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d",
-                 HR_FORMAT_PARAMS(csr),
-                 p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()),
-                 csr->age_in_surv_rate_group_cond());
-    csr = next;
-  }
+
+  G1PrintCollectionSetClosure cl(st);
+  iterate(&cl);
 }
 #endif // !PRODUCT
 
@@ -281,7 +357,6 @@
 
   guarantee(target_pause_time_ms > 0.0,
             "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms);
-  guarantee(_head == NULL, "Precondition");
 
   size_t pending_cards = _policy->pending_cards();
   double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards);
@@ -305,7 +380,6 @@
   // Clear the fields that point to the survivor list - they are all young now.
   survivors->convert_to_eden();
 
-  _head = _inc_head;
   _bytes_used_before = _inc_bytes_used_before;
   time_remaining_ms = MAX2(time_remaining_ms - _inc_predicted_elapsed_time_ms, 0.0);
 
@@ -422,23 +496,41 @@
 }
 
 #ifdef ASSERT
-void G1CollectionSet::verify_young_cset_indices() const {
-  ResourceMark rm;
-  uint* heap_region_indices = NEW_RESOURCE_ARRAY(uint, young_region_length());
-  for (uint i = 0; i < young_region_length(); ++i) {
-    heap_region_indices[i] = (uint)-1;
+class G1VerifyYoungCSetIndicesClosure : public HeapRegionClosure {
+private:
+  size_t _young_length;
+  int* _heap_region_indices;
+public:
+  G1VerifyYoungCSetIndicesClosure(size_t young_length) : HeapRegionClosure(), _young_length(young_length) {
+    _heap_region_indices = NEW_C_HEAP_ARRAY(int, young_length, mtGC);
+    for (size_t i = 0; i < young_length; i++) {
+      _heap_region_indices[i] = -1;
+    }
+  }
+  ~G1VerifyYoungCSetIndicesClosure() {
+    FREE_C_HEAP_ARRAY(int, _heap_region_indices);
   }
 
-  for (HeapRegion* hr = _inc_head; hr != NULL; hr = hr->next_in_collection_set()) {
-    const int idx = hr->young_index_in_cset();
-    assert(idx > -1, "must be set for all inc cset regions");
-    assert((uint)idx < young_region_length(), "young cset index too large");
+  virtual bool doHeapRegion(HeapRegion* r) {
+    const int idx = r->young_index_in_cset();
+
+    assert(idx > -1, "Young index must be set for all regions in the incremental collection set but is not for region %u.", r->hrm_index());
+    assert((size_t)idx < _young_length, "Young cset index too large for region %u", r->hrm_index());
+
+    assert(_heap_region_indices[idx] == -1,
+           "Index %d used by multiple regions, first use by region %u, second by region %u",
+           idx, _heap_region_indices[idx], r->hrm_index());
 
-    assert(heap_region_indices[idx] == (uint)-1,
-           "index %d used by multiple regions, first use by %u, second by %u",
-           idx, heap_region_indices[idx], hr->hrm_index());
+    _heap_region_indices[idx] = r->hrm_index();
+
+    return false;
+  }
+};
 
-    heap_region_indices[idx] = hr->hrm_index();
-  }
+void G1CollectionSet::verify_young_cset_indices() const {
+  assert_at_safepoint(true);
+
+  G1VerifyYoungCSetIndicesClosure cl(_collection_set_cur_length);
+  iterate(&cl);
 }
 #endif
--- a/hotspot/src/share/vm/gc/g1/g1CollectionSet.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectionSet.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -47,10 +47,15 @@
   uint _survivor_region_length;
   uint _old_region_length;
 
-  // The head of the list (via "next_in_collection_set()") representing the
-  // current collection set. Set from the incrementally built collection
-  // set at the start of the pause.
-  HeapRegion* _head;
+  // The actual collection set as a set of region indices.
+  // All entries in _collection_set_regions below _collection_set_cur_length are
+  // assumed to be valid entries.
+  // We assume that at any time there is at most only one writer and (one or more)
+  // concurrent readers. This means we are good with using storestore and loadload
+  // barriers on the writer and reader respectively only.
+  uint* _collection_set_regions;
+  volatile size_t _collection_set_cur_length;
+  size_t _collection_set_max_length;
 
   // The number of bytes in the collection set before the pause. Set from
   // the incrementally built collection set at the start of an evacuation
@@ -71,12 +76,6 @@
 
   CSetBuildType _inc_build_state;
 
-  // The head of the incrementally built collection set.
-  HeapRegion* _inc_head;
-
-  // The tail of the incrementally built collection set.
-  HeapRegion* _inc_tail;
-
   // The number of bytes in the incrementally built collection set.
   // Used to set _collection_set_bytes_used_before at the start of
   // an evacuation pause.
@@ -105,8 +104,6 @@
   // See the comment for _inc_recorded_rs_lengths_diffs.
   double _inc_predicted_elapsed_time_ms_diffs;
 
-  uint _inc_region_length;
-
   G1CollectorState* collector_state();
   G1GCPhaseTimes* phase_times();
 
@@ -117,6 +114,9 @@
   G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy);
   ~G1CollectionSet();
 
+  // Initializes the collection set giving the maximum possible length of the collection set.
+  void initialize(uint max_region_length);
+
   CollectionSetChooser* cset_chooser();
 
   void init_region_lengths(uint eden_cset_region_length,
@@ -133,35 +133,30 @@
   uint survivor_region_length() const { return _survivor_region_length; }
   uint old_region_length() const      { return _old_region_length;      }
 
-  // Incremental CSet Support
-
-  // The head of the incrementally built collection set.
-  HeapRegion* inc_head() { return _inc_head; }
-
-  // The tail of the incrementally built collection set.
-  HeapRegion* inc_tail() { return _inc_tail; }
+  // Incremental collection set support
 
   // Initialize incremental collection set info.
   void start_incremental_building();
 
-  // Perform any final calculations on the incremental CSet fields
+  // Perform any final calculations on the incremental collection set fields
   // before we can use them.
   void finalize_incremental_building();
 
-  void clear_incremental() {
-    _inc_head = NULL;
-    _inc_tail = NULL;
-    _inc_region_length = 0;
-  }
+  // Reset the contents of the collection set.
+  void clear();
+
+  // Iterate over the collection set, applying the given HeapRegionClosure on all of them.
+  // If may_be_aborted is true, iteration may be aborted using the return value of the
+  // called closure method.
+  void iterate(HeapRegionClosure* cl) const;
 
-  // Stop adding regions to the incremental collection set
-  void stop_incremental_building() { _inc_build_state = Inactive; }
+  // Iterate over the collection set, applying the given HeapRegionClosure on all of them,
+  // trying to optimally spread out starting position of total_workers workers given the
+  // caller's worker_id.
+  void iterate_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const;
 
-  // The head of the list (via "next_in_collection_set()") representing the
-  // current collection set.
-  HeapRegion* head() { return _head; }
-
-  void clear_head() { _head = NULL; }
+  // Stop adding regions to the incremental collection set.
+  void stop_incremental_building() { _inc_build_state = Inactive; }
 
   size_t recorded_rs_lengths() { return _recorded_rs_lengths; }
 
@@ -174,33 +169,32 @@
   }
 
   // Choose a new collection set.  Marks the chosen regions as being
-  // "in_collection_set", and links them together.  The head and number of
-  // the collection set are available via access methods.
+  // "in_collection_set".
   double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors);
   void finalize_old_part(double time_remaining_ms);
 
-  // Add old region "hr" to the CSet.
+  // Add old region "hr" to the collection set.
   void add_old_region(HeapRegion* hr);
 
   // Update information about hr in the aggregated information for
   // the incrementally built collection set.
   void update_young_region_prediction(HeapRegion* hr, size_t new_rs_length);
 
-  // Add hr to the LHS of the incremental collection set.
+  // Add eden region to the collection set.
   void add_eden_region(HeapRegion* hr);
 
-  // Add hr to the RHS of the incremental collection set.
+  // Add survivor region to the collection set.
   void add_survivor_regions(HeapRegion* hr);
 
 #ifndef PRODUCT
-  void print(HeapRegion* list_head, outputStream* st);
+  bool verify_young_ages();
+
+  void print(outputStream* st);
 #endif // !PRODUCT
 
 private:
-  // Update the incremental cset information when adding a region
-  // (should not be called directly).
+  // Update the incremental collection set information when adding a region.
   void add_young_region_common(HeapRegion* hr);
-
 };
 
 #endif // SHARE_VM_GC_G1_G1COLLECTIONSET_HPP
--- a/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -394,37 +394,6 @@
   }
 }
 
-#ifndef PRODUCT
-bool G1DefaultPolicy::verify_young_ages() {
-  bool ret = true;
-
-  for (HeapRegion* curr = _collection_set->inc_head();
-       curr != NULL;
-       curr = curr->next_in_collection_set()) {
-    guarantee(curr->is_young(), "Region must be young");
-
-    SurvRateGroup* group = curr->surv_rate_group();
-
-    if (group == NULL) {
-      log_error(gc, verify)("## encountered NULL surv_rate_group in young region");
-      ret = false;
-    }
-
-    if (curr->age_in_surv_rate_group() < 0) {
-      log_error(gc, verify)("## encountered negative age in young region");
-      ret = false;
-    }
-  }
-
-  if (!ret) {
-    LogStreamHandle(Error, gc, verify) log;
-    _collection_set->print(_collection_set->inc_head(), &log);
-  }
-
-  return ret;
-}
-#endif // PRODUCT
-
 void G1DefaultPolicy::record_full_collection_start() {
   _full_collection_start_sec = os::elapsedTime();
   // Release the future to-space so that it is available for compaction into.
@@ -488,7 +457,7 @@
   _short_lived_surv_rate_group->stop_adding_regions();
   _survivors_age_table.clear();
 
-  assert( verify_young_ages(), "region age verification" );
+  assert(_g1->collection_set()->verify_young_ages(), "region age verification failed");
 }
 
 void G1DefaultPolicy::record_concurrent_mark_init_end(double mark_init_elapsed_time_ms) {
--- a/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -89,10 +89,6 @@
 
   size_t _rs_lengths_prediction;
 
-#ifndef PRODUCT
-  bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group);
-#endif // PRODUCT
-
   size_t _pending_cards;
 
   // The amount of allocated bytes in old gen during the last mutator and the following
@@ -116,10 +112,6 @@
     hr->install_surv_rate_group(_survivor_surv_rate_group);
   }
 
-#ifndef PRODUCT
-  bool verify_young_ages();
-#endif // PRODUCT
-
   void record_max_rs_lengths(size_t rs_lengths) {
     _max_rs_lengths = rs_lengths;
   }
--- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -251,6 +251,5 @@
 void G1ParRemoveSelfForwardPtrsTask::work(uint worker_id) {
   RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id, &_hrclaimer);
 
-  HeapRegion* hr = _g1h->start_cset_region_for_worker(worker_id);
-  _g1h->collection_set_iterate_from(hr, &rsfp_cl);
+  _g1h->collection_set_iterate_from(&rsfp_cl, worker_id);
 }
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -580,15 +580,20 @@
   }
 }
 
-void G1HeapVerifier::verify_dirty_young_list(HeapRegion* head) {
-  G1SATBCardTableModRefBS* ct_bs = _g1h->g1_barrier_set();
-  for (HeapRegion* hr = head; hr != NULL; hr = hr->next_in_collection_set()) {
-    verify_dirty_region(hr);
+class G1VerifyDirtyYoungListClosure : public HeapRegionClosure {
+private:
+  G1HeapVerifier* _verifier;
+public:
+  G1VerifyDirtyYoungListClosure(G1HeapVerifier* verifier) : HeapRegionClosure(), _verifier(verifier) { }
+  virtual bool doHeapRegion(HeapRegion* r) {
+    _verifier->verify_dirty_region(r);
+    return false;
   }
-}
+};
 
 void G1HeapVerifier::verify_dirty_young_regions() {
-  verify_dirty_young_list(_g1h->collection_set()->inc_head());
+  G1VerifyDirtyYoungListClosure cl(this);
+  _g1h->collection_set()->iterate(&cl);
 }
 
 bool G1HeapVerifier::verify_no_bits_over_tams(const char* bitmap_name, G1CMBitMapRO* bitmap,
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -108,7 +108,6 @@
 
   void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
   void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
-  void verify_dirty_young_list(HeapRegion* head) PRODUCT_RETURN;
   void verify_dirty_young_regions() PRODUCT_RETURN;
 };
 
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -382,10 +382,8 @@
                               uint worker_i) {
   double rs_time_start = os::elapsedTime();
 
-  HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i);
-
   G1ScanRSClosure cl(_scan_state, oops_in_heap_closure, heap_region_codeblobs, worker_i);
-  _g1->collection_set_iterate_from(startRegion, &cl);
+  _g1->collection_set_iterate_from(&cl, worker_i);
 
    double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) -
                               cl.strong_code_root_scan_time_sec();
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -154,8 +154,8 @@
 }
 
 void G1StringDedupQueue::print_statistics() {
-  log_debug(gc, stringdedup)("   [Queue]");
-  log_debug(gc, stringdedup)("      [Dropped: " UINTX_FORMAT "]", _queue->_dropped);
+  log_debug(gc, stringdedup)("  Queue");
+  log_debug(gc, stringdedup)("    Dropped: " UINTX_FORMAT, _queue->_dropped);
 }
 
 void G1StringDedupQueue::verify() {
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupStat.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupStat.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,9 @@
   _idle(0),
   _exec(0),
   _block(0),
-  _start(0.0),
+  _start_concurrent(0.0),
+  _end_concurrent(0.0),
+  _start_phase(0.0),
   _idle_elapsed(0.0),
   _exec_elapsed(0.0),
   _block_elapsed(0.0) {
@@ -69,7 +71,13 @@
   _block_elapsed       += stat._block_elapsed;
 }
 
-void G1StringDedupStat::print_summary(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
+void G1StringDedupStat::print_start(const G1StringDedupStat& last_stat) {
+  log_info(gc, stringdedup)(
+     "Concurrent String Deduplication (" G1_STRDEDUP_TIME_FORMAT ")",
+     G1_STRDEDUP_TIME_PARAM(last_stat._start_concurrent));
+}
+
+void G1StringDedupStat::print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
   double total_deduped_bytes_percent = 0.0;
 
   if (total_stat._new_bytes > 0) {
@@ -79,13 +87,16 @@
 
   log_info(gc, stringdedup)(
     "Concurrent String Deduplication "
-    G1_STRDEDUP_BYTES_FORMAT_NS "->" G1_STRDEDUP_BYTES_FORMAT_NS "(" G1_STRDEDUP_BYTES_FORMAT_NS "), avg "
-    G1_STRDEDUP_PERCENT_FORMAT_NS ", " G1_STRDEDUP_TIME_FORMAT,
+    G1_STRDEDUP_BYTES_FORMAT_NS "->" G1_STRDEDUP_BYTES_FORMAT_NS "(" G1_STRDEDUP_BYTES_FORMAT_NS ") "
+    "avg " G1_STRDEDUP_PERCENT_FORMAT_NS " "
+    "(" G1_STRDEDUP_TIME_FORMAT ", " G1_STRDEDUP_TIME_FORMAT ") " G1_STRDEDUP_TIME_FORMAT_MS,
     G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes),
     G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes),
     G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes),
     total_deduped_bytes_percent,
-    last_stat._exec_elapsed);
+    G1_STRDEDUP_TIME_PARAM(last_stat._start_concurrent),
+    G1_STRDEDUP_TIME_PARAM(last_stat._end_concurrent),
+    G1_STRDEDUP_TIME_PARAM_MS(last_stat._exec_elapsed));
 }
 
 void G1StringDedupStat::print_statistics(const G1StringDedupStat& stat, bool total) {
@@ -134,23 +145,31 @@
 
   if (total) {
     log_debug(gc, stringdedup)(
-      "   [Total Exec: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT ", Idle: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT "]",
-      stat._exec, stat._exec_elapsed, stat._idle, stat._idle_elapsed, stat._block, stat._block_elapsed);
+      "  Total Exec: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS
+      ", Idle: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS
+      ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS,
+      stat._exec, G1_STRDEDUP_TIME_PARAM_MS(stat._exec_elapsed),
+      stat._idle, G1_STRDEDUP_TIME_PARAM_MS(stat._idle_elapsed),
+      stat._block, G1_STRDEDUP_TIME_PARAM_MS(stat._block_elapsed));
   } else {
     log_debug(gc, stringdedup)(
-      "   [Last Exec: " G1_STRDEDUP_TIME_FORMAT ", Idle: " G1_STRDEDUP_TIME_FORMAT ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT "]",
-      stat._exec_elapsed, stat._idle_elapsed, stat._block, stat._block_elapsed);
+      "  Last Exec: " G1_STRDEDUP_TIME_FORMAT_MS
+      ", Idle: " G1_STRDEDUP_TIME_FORMAT_MS
+      ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS,
+      G1_STRDEDUP_TIME_PARAM_MS(stat._exec_elapsed),
+      G1_STRDEDUP_TIME_PARAM_MS(stat._idle_elapsed),
+      stat._block, G1_STRDEDUP_TIME_PARAM_MS(stat._block_elapsed));
   }
-  log_debug(gc, stringdedup)("      [Inspected:    " G1_STRDEDUP_OBJECTS_FORMAT "]", stat._inspected);
-  log_debug(gc, stringdedup)("         [Skipped:   " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._skipped, skipped_percent);
-  log_debug(gc, stringdedup)("         [Hashed:    " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._hashed, hashed_percent);
-  log_debug(gc, stringdedup)("         [Known:     " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._known, known_percent);
-  log_debug(gc, stringdedup)("         [New:       " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "]",
+  log_debug(gc, stringdedup)("    Inspected:    " G1_STRDEDUP_OBJECTS_FORMAT, stat._inspected);
+  log_debug(gc, stringdedup)("      Skipped:    " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._skipped, skipped_percent);
+  log_debug(gc, stringdedup)("      Hashed:     " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._hashed, hashed_percent);
+  log_debug(gc, stringdedup)("      Known:      " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._known, known_percent);
+  log_debug(gc, stringdedup)("      New:        " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT,
                              stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes));
-  log_debug(gc, stringdedup)("      [Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]",
+  log_debug(gc, stringdedup)("    Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
                              stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent);
-  log_debug(gc, stringdedup)("         [Young:     " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]",
+  log_debug(gc, stringdedup)("      Young:      " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
                              stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent);
-  log_debug(gc, stringdedup)("         [Old:       " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]",
+  log_debug(gc, stringdedup)("      Old:        " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
                              stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent);
 }
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupStat.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupStat.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,11 +30,14 @@
 
 // Macros for GC log output formating
 #define G1_STRDEDUP_OBJECTS_FORMAT         UINTX_FORMAT_W(12)
-#define G1_STRDEDUP_TIME_FORMAT            "%1.7lf secs"
-#define G1_STRDEDUP_PERCENT_FORMAT         "%5.1lf%%"
-#define G1_STRDEDUP_PERCENT_FORMAT_NS      "%.1lf%%"
-#define G1_STRDEDUP_BYTES_FORMAT           "%8.1lf%s"
-#define G1_STRDEDUP_BYTES_FORMAT_NS        "%.1lf%s"
+#define G1_STRDEDUP_TIME_FORMAT            "%.3fs"
+#define G1_STRDEDUP_TIME_PARAM(time)       (time)
+#define G1_STRDEDUP_TIME_FORMAT_MS         "%.3fms"
+#define G1_STRDEDUP_TIME_PARAM_MS(time)    ((time) * MILLIUNITS)
+#define G1_STRDEDUP_PERCENT_FORMAT         "%5.1f%%"
+#define G1_STRDEDUP_PERCENT_FORMAT_NS      "%.1f%%"
+#define G1_STRDEDUP_BYTES_FORMAT           "%8.1f%s"
+#define G1_STRDEDUP_BYTES_FORMAT_NS        "%.1f%s"
 #define G1_STRDEDUP_BYTES_PARAM(bytes)     byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes))
 
 //
@@ -60,7 +63,9 @@
   uintx  _block;
 
   // Time spent by the deduplication thread in different phases
-  double _start;
+  double _start_concurrent;
+  double _end_concurrent;
+  double _start_phase;
   double _idle_elapsed;
   double _exec_elapsed;
   double _block_elapsed;
@@ -104,38 +109,41 @@
   }
 
   void mark_idle() {
-    _start = os::elapsedTime();
+    _start_phase = os::elapsedTime();
     _idle++;
   }
 
   void mark_exec() {
     double now = os::elapsedTime();
-    _idle_elapsed = now - _start;
-    _start = now;
+    _idle_elapsed = now - _start_phase;
+    _start_phase = now;
+    _start_concurrent = now;
     _exec++;
   }
 
   void mark_block() {
     double now = os::elapsedTime();
-    _exec_elapsed += now - _start;
-    _start = now;
+    _exec_elapsed += now - _start_phase;
+    _start_phase = now;
     _block++;
   }
 
   void mark_unblock() {
     double now = os::elapsedTime();
-    _block_elapsed += now - _start;
-    _start = now;
+    _block_elapsed += now - _start_phase;
+    _start_phase = now;
   }
 
   void mark_done() {
     double now = os::elapsedTime();
-    _exec_elapsed += now - _start;
+    _exec_elapsed += now - _start_phase;
+    _end_concurrent = now;
   }
 
   void add(const G1StringDedupStat& stat);
 
-  static void print_summary(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
+  static void print_start(const G1StringDedupStat& last_stat);
+  static void print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
   static void print_statistics(const G1StringDedupStat& stat, bool total);
 };
 
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -196,7 +196,8 @@
   }
 
   double end = os::elapsedTime();
-  log_trace(gc, stringdedup)("Deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT, count, end - start);
+  log_trace(gc, stringdedup)("Deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT_MS,
+                             count, G1_STRDEDUP_TIME_PARAM_MS(end - start));
 }
 
 G1StringDedupTable*      G1StringDedupTable::_table = NULL;
@@ -610,14 +611,14 @@
 
 void G1StringDedupTable::print_statistics() {
   Log(gc, stringdedup) log;
-  log.debug("   [Table]");
-  log.debug("      [Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS "]",
+  log.debug("  Table");
+  log.debug("    Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS,
             G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)));
-  log.debug("      [Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT "]", _table->_size, _min_size, _max_size);
-  log.debug("      [Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT "]",
+  log.debug("    Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT, _table->_size, _min_size, _max_size);
+  log.debug("    Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT,
             _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed);
-  log.debug("      [Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")]",
+  log.debug("    Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")",
             _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0);
-  log.debug("      [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x]", _rehash_count, _rehash_threshold, _table->_hash_seed);
-  log.debug("      [Age Threshold: " UINTX_FORMAT "]", StringDeduplicationAgeThreshold);
+  log.debug("    Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x", _rehash_count, _rehash_threshold, _table->_hash_seed);
+  log.debug("    Age Threshold: " UINTX_FORMAT, StringDeduplicationAgeThreshold);
 }
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -103,6 +103,7 @@
       SuspendibleThreadSetJoiner sts_join;
 
       stat.mark_exec();
+      print_start(stat);
 
       // Process the queue
       for (;;) {
@@ -123,9 +124,8 @@
 
       stat.mark_done();
 
-      // Print statistics
       total_stat.add(stat);
-      print(stat, total_stat);
+      print_end(stat, total_stat);
     }
 
     G1StringDedupTable::clean_entry_cache();
@@ -136,14 +136,16 @@
   G1StringDedupQueue::cancel_wait();
 }
 
-void G1StringDedupThread::print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
-  if (log_is_enabled(Info, gc, stringdedup)) {
-    G1StringDedupStat::print_summary(last_stat, total_stat);
-    if (log_is_enabled(Debug, gc, stringdedup)) {
-      G1StringDedupStat::print_statistics(last_stat, false);
-      G1StringDedupStat::print_statistics(total_stat, true);
-      G1StringDedupTable::print_statistics();
-      G1StringDedupQueue::print_statistics();
-    }
+void G1StringDedupThread::print_start(const G1StringDedupStat& last_stat) {
+  G1StringDedupStat::print_start(last_stat);
+}
+
+void G1StringDedupThread::print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
+  G1StringDedupStat::print_end(last_stat, total_stat);
+  if (log_is_enabled(Debug, gc, stringdedup)) {
+    G1StringDedupStat::print_statistics(last_stat, false);
+    G1StringDedupStat::print_statistics(total_stat, true);
+    G1StringDedupTable::print_statistics();
+    G1StringDedupQueue::print_statistics();
   }
 }
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -43,7 +43,8 @@
   G1StringDedupThread();
   ~G1StringDedupThread();
 
-  void print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
+  void print_start(const G1StringDedupStat& last_stat);
+  void print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
 
   void run_service();
   void stop_service();
--- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -71,38 +71,51 @@
   _monitor.notify();
 }
 
+class G1YoungRemSetSamplingClosure : public HeapRegionClosure {
+  SuspendibleThreadSetJoiner* _sts;
+  size_t _regions_visited;
+  size_t _sampled_rs_lengths;
+public:
+  G1YoungRemSetSamplingClosure(SuspendibleThreadSetJoiner* sts) :
+    HeapRegionClosure(), _sts(sts), _regions_visited(0), _sampled_rs_lengths(0) { }
+
+  virtual bool doHeapRegion(HeapRegion* r) {
+    size_t rs_length = r->rem_set()->occupied();
+    _sampled_rs_lengths += rs_length;
+
+    // Update the collection set policy information for this region
+    G1CollectedHeap::heap()->collection_set()->update_young_region_prediction(r, rs_length);
+
+    _regions_visited++;
+
+    if (_regions_visited == 10) {
+      if (_sts->should_yield()) {
+        _sts->yield();
+        // A gc may have occurred and our sampling data is stale and further
+        // traversal of the collection set is unsafe
+        return true;
+      }
+      _regions_visited = 0;
+    }
+    return false;
+  }
+
+  size_t sampled_rs_lengths() const { return _sampled_rs_lengths; }
+};
+
 void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() {
   SuspendibleThreadSetJoiner sts;
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
   G1Policy* g1p = g1h->g1_policy();
-  G1CollectionSet* g1cs = g1h->collection_set();
+
   if (g1p->adaptive_young_list_length()) {
-    int regions_visited = 0;
-    HeapRegion* hr = g1cs->inc_head();
-    size_t sampled_rs_lengths = 0;
-
-    while (hr != NULL) {
-      size_t rs_length = hr->rem_set()->occupied();
-      sampled_rs_lengths += rs_length;
-
-      // Update the collection set policy information for this region
-      g1cs->update_young_region_prediction(hr, rs_length);
-
-      ++regions_visited;
+    G1YoungRemSetSamplingClosure cl(&sts);
 
-      // we try to yield every time we visit 10 regions
-      if (regions_visited == 10) {
-        if (sts.should_yield()) {
-          sts.yield();
-          // A gc may have occurred and our sampling data is stale and further
-          // traversal of the collection set is unsafe
-          return;
-        }
-        regions_visited = 0;
-      }
-      assert(hr == g1cs->inc_tail() || hr->next_in_collection_set() != NULL, "next should only be null at tail of icset");
-      hr = hr->next_in_collection_set();
+    G1CollectionSet* g1cs = g1h->collection_set();
+    g1cs->iterate(&cl);
+
+    if (cl.complete()) {
+      g1p->revise_young_list_target_length_if_necessary(cl.sampled_rs_lengths());
     }
-    g1p->revise_young_list_target_length_if_necessary(sampled_rs_lengths);
   }
 }
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -284,7 +284,6 @@
     _hrm_index(hrm_index),
     _allocation_context(AllocationContext::system()),
     _humongous_start_region(NULL),
-    _next_in_special_set(NULL),
     _evacuation_failed(false),
     _prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0),
     _next(NULL), _prev(NULL),
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -261,12 +261,6 @@
   // True iff an attempt to evacuate an object in the region failed.
   bool _evacuation_failed;
 
-  // A heap region may be a member one of a number of special subsets, each
-  // represented as linked lists through the field below.  Currently, there
-  // is only one set:
-  //   The collection set.
-  HeapRegion* _next_in_special_set;
-
   // Fields used by the HeapRegionSetBase class and subclasses.
   HeapRegion* _next;
   HeapRegion* _prev;
@@ -476,9 +470,6 @@
 
   inline bool in_collection_set() const;
 
-  inline HeapRegion* next_in_collection_set() const;
-  inline void set_next_in_collection_set(HeapRegion* r);
-
   void set_allocation_context(AllocationContext_t context) {
     _allocation_context = context;
   }
@@ -744,7 +735,7 @@
 // Terminates the iteration when the "doHeapRegion" method returns "true".
 class HeapRegionClosure : public StackObj {
   friend class HeapRegionManager;
-  friend class G1CollectedHeap;
+  friend class G1CollectionSet;
 
   bool _complete;
   void incomplete() { _complete = false; }
--- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -230,18 +230,4 @@
   return G1CollectedHeap::heap()->is_in_cset(this);
 }
 
-inline HeapRegion* HeapRegion::next_in_collection_set() const {
-  assert(in_collection_set(), "should only invoke on member of CS.");
-  assert(_next_in_special_set == NULL ||
-         _next_in_special_set->in_collection_set(),
-         "Malformed CS.");
-  return _next_in_special_set;
-}
-
-void HeapRegion::set_next_in_collection_set(HeapRegion* r) {
-  assert(in_collection_set(), "should only invoke on member of CS.");
-  assert(r == NULL || r->in_collection_set(), "Malformed CS.");
-  _next_in_special_set = r;
-}
-
 #endif // SHARE_VM_GC_G1_HEAPREGION_INLINE_HPP
--- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -386,13 +386,21 @@
 
 void GCTaskManager::add_workers(bool initializing) {
   os::ThreadType worker_type = os::pgc_thread;
+  uint previous_created_workers = _created_workers;
+
   _created_workers = WorkerManager::add_workers(this,
                                                 _active_workers,
-                                                (uint) _workers,
+                                                _workers,
                                                 _created_workers,
                                                 worker_type,
                                                 initializing);
   _active_workers = MIN2(_created_workers, _active_workers);
+
+  WorkerManager::log_worker_creation(this, previous_created_workers, _active_workers, _created_workers, initializing);
+}
+
+const char* GCTaskManager::group_name() {
+  return "ParGC Thread";
 }
 
 void GCTaskManager::initialize() {
--- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -556,6 +556,8 @@
   GCTaskThread* install_worker(uint worker_id);
   // Add GC workers as needed.
   void add_workers(bool initializing);
+  // Base name (without worker id #) of threads.
+  const char* group_name();
 };
 
 //
--- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -45,7 +45,7 @@
   _time_stamp_index(0)
 {
   set_id(which);
-  set_name("ParGC Thread#%d", which);
+  set_name("%s#%d", manager->group_name(), which);
 }
 
 GCTaskThread::~GCTaskThread() {
--- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -55,6 +55,7 @@
     return new GCTaskThread(manager, which, processor_id);
   }
  public:
+
   static void destroy(GCTaskThread* manager) {
     if (manager != NULL) {
       delete manager;
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -159,6 +159,8 @@
   inline static void post_allocation_setup_array(KlassHandle klass,
                                                  HeapWord* obj, int length);
 
+  inline static void post_allocation_setup_class(KlassHandle klass, HeapWord* obj, int size);
+
   // Clears an allocated object.
   inline static void init_obj(HeapWord* obj, size_t size);
 
@@ -300,6 +302,7 @@
   inline static oop obj_allocate(KlassHandle klass, int size, TRAPS);
   inline static oop array_allocate(KlassHandle klass, int size, int length, TRAPS);
   inline static oop array_allocate_nozero(KlassHandle klass, int size, int length, TRAPS);
+  inline static oop class_allocate(KlassHandle klass, int size, TRAPS);
 
   inline static void post_allocation_install_obj_klass(KlassHandle klass,
                                                        oop obj);
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_GC_SHARED_COLLECTEDHEAP_INLINE_HPP
 #define SHARE_VM_GC_SHARED_COLLECTEDHEAP_INLINE_HPP
 
+#include "classfile/javaClasses.hpp"
 #include "gc/shared/allocTracer.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "gc/shared/threadLocalAllocBuffer.inline.hpp"
@@ -96,6 +97,22 @@
   post_allocation_notify(klass, (oop)obj, size);
 }
 
+void CollectedHeap::post_allocation_setup_class(KlassHandle klass,
+                                                HeapWord* obj,
+                                                int size) {
+  // Set oop_size field before setting the _klass field
+  // in post_allocation_setup_common() because the klass field
+  // indicates that the object is parsable by concurrent GC.
+  oop new_cls = (oop)obj;
+  assert(size > 0, "oop_size must be positive.");
+  java_lang_Class::set_oop_size(new_cls, size);
+  post_allocation_setup_common(klass, obj);
+  assert(Universe::is_bootstrapping() ||
+         !new_cls->is_array(), "must not be an array");
+  // notify jvmti and dtrace
+  post_allocation_notify(klass, new_cls, size);
+}
+
 void CollectedHeap::post_allocation_setup_array(KlassHandle klass,
                                                 HeapWord* obj,
                                                 int length) {
@@ -207,6 +224,16 @@
   return (oop)obj;
 }
 
+oop CollectedHeap::class_allocate(KlassHandle klass, int size, TRAPS) {
+  debug_only(check_for_valid_allocation_state());
+  assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");
+  assert(size >= 0, "int won't convert to size_t");
+  HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
+  post_allocation_setup_class(klass, obj, size); // set oop_size
+  NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
+  return (oop)obj;
+}
+
 oop CollectedHeap::array_allocate(KlassHandle klass,
                                   int size,
                                   int length,
--- a/hotspot/src/share/vm/gc/shared/workerManager.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/workerManager.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -47,18 +47,18 @@
   // threads and a failure would not be optimal but should not be fatal.
   template <class WorkerType>
   static uint add_workers (WorkerType* holder,
-                   uint active_workers,
-                   uint total_workers,
-                   uint created_workers,
-                   os::ThreadType worker_type,
-                   bool initializing) {
+                           uint active_workers,
+                           uint total_workers,
+                           uint created_workers,
+                           os::ThreadType worker_type,
+                           bool initializing) {
     uint start = created_workers;
     uint end = MIN2(active_workers, total_workers);
     for (uint worker_id = start; worker_id < end; worker_id += 1) {
       WorkerThread* new_worker = holder->install_worker(worker_id);
       assert(new_worker != NULL, "Failed to allocate GangWorker");
       if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
-        if(initializing) {
+        if (initializing) {
           vm_exit_out_of_memory(0, OOM_MALLOC_ERROR,
                   "Cannot create worker GC thread. Out of system resources.");
         }
@@ -67,11 +67,21 @@
       os::start_thread(new_worker);
     }
 
-    log_trace(gc, task)("AdaptiveSizePolicy::add_workers() : "
-       "active_workers: %u created_workers: %u",
-       active_workers, created_workers);
+    return created_workers;
+  }
 
-    return created_workers;
+  // Log (at trace level) a change in the number of created workers.
+  template <class WorkerType>
+  static void log_worker_creation(WorkerType* holder,
+                                  uint previous_created_workers,
+                                  uint active_workers,
+                                  uint created_workers,
+                                  bool initializing) {
+    if (previous_created_workers < created_workers) {
+      const char* initializing_msg =  initializing ? "Adding initial" : "Creating additional";
+      log_trace(gc, task)("%s %s(s) previously created workers %u active workers %u total created workers %u",
+                          initializing_msg, holder->group_name(), previous_created_workers, active_workers, created_workers);
+    }
   }
 };
 #endif // SHARE_VM_GC_SHARED_WORKERMANAGER_HPP
--- a/hotspot/src/share/vm/gc/shared/workgroup.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -66,6 +66,7 @@
   } else {
     worker_type = os::pgc_thread;
   }
+  uint previous_created_workers = _created_workers;
 
   _created_workers = WorkerManager::add_workers(this,
                                                 active_workers,
@@ -74,6 +75,8 @@
                                                 worker_type,
                                                 initializing);
   _active_workers = MIN2(_created_workers, _active_workers);
+
+  WorkerManager::log_worker_creation(this, previous_created_workers, _active_workers, _created_workers, initializing);
 }
 
 AbstractGangWorker* AbstractWorkGang::worker(uint i) const {
--- a/hotspot/src/share/vm/gc/shared/workgroup.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -176,6 +176,9 @@
   // Return the Ith worker.
   AbstractGangWorker* worker(uint i) const;
 
+  // Base name (without worker id #) of threads.
+  const char* group_name() { return name(); }
+
   void threads_do(ThreadClosure* tc) const;
 
   // Create a GC worker and install it into the work gang.
--- a/hotspot/src/share/vm/interpreter/bytecodeStream.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/bytecodeStream.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,12 +31,12 @@
   // set next bytecode position
   address bcp = RawBytecodeStream::bcp();
   address end = method()->code_base() + end_bci();
-  int l = Bytecodes::raw_special_length_at(bcp, end);
-  if (l <= 0 || (_bci + l) > _end_bci) {
+  int len = Bytecodes::raw_special_length_at(bcp, end);
+  // Very large tableswitch or lookupswitch size can cause _next_bci to overflow.
+  if (len <= 0 || (_bci > _end_bci - len) || (_bci - len >= _next_bci)) {
     code = Bytecodes::_illegal;
   } else {
-    _next_bci += l;
-    assert(_bci < _next_bci, "length must be > 0");
+    _next_bci += len;
     // set attributes
     _is_wide = false;
     // check for special (uncommon) cases
--- a/hotspot/src/share/vm/interpreter/bytecodeStream.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/bytecodeStream.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -135,12 +135,15 @@
     code        = Bytecodes::code_or_bp_at(bcp);
 
     // set next bytecode position
-    int l = Bytecodes::length_for(code);
-    if (l > 0 && (_bci + l) <= _end_bci) {
+    int len = Bytecodes::length_for(code);
+    if (len > 0 && (_bci <= _end_bci - len)) {
       assert(code != Bytecodes::_wide && code != Bytecodes::_tableswitch
              && code != Bytecodes::_lookupswitch, "can't be special bytecode");
       _is_wide = false;
-      _next_bci += l;
+      _next_bci += len;
+      if (_next_bci <= _bci) { // Check for integer overflow
+        code = Bytecodes::_illegal;
+      }
       _raw_code = code;
       return code;
     } else {
@@ -189,19 +192,23 @@
       // note that we cannot advance before having the
       // tty bytecode otherwise the stepping is wrong!
       // (carefull: length_for(...) must be used first!)
-      int l = Bytecodes::length_for(code);
-      if (l == 0) l = Bytecodes::length_at(_method(), bcp);
-      _next_bci  += l;
-      assert(_bci < _next_bci, "length must be > 0");
-      // set attributes
-      _is_wide      = false;
-      // check for special (uncommon) cases
-      if (code == Bytecodes::_wide) {
-        raw_code = (Bytecodes::Code)bcp[1];
-        code = raw_code;  // wide BCs are always Java-normal
-        _is_wide = true;
+      int len = Bytecodes::length_for(code);
+      if (len == 0) len = Bytecodes::length_at(_method(), bcp);
+      if (len <= 0 || (_bci > _end_bci - len) || (_bci - len >= _next_bci)) {
+        raw_code = code = Bytecodes::_illegal;
+      } else {
+        _next_bci  += len;
+        assert(_bci < _next_bci, "length must be > 0");
+        // set attributes
+        _is_wide      = false;
+        // check for special (uncommon) cases
+        if (code == Bytecodes::_wide) {
+          raw_code = (Bytecodes::Code)bcp[1];
+          code = raw_code;  // wide BCs are always Java-normal
+          _is_wide = true;
+        }
+        assert(Bytecodes::is_java_code(code), "sanity check");
       }
-      assert(Bytecodes::is_java_code(code), "sanity check");
     }
     _raw_code = raw_code;
     _code = code;
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -576,27 +576,27 @@
   // compute auxiliary field attributes
   TosState state  = as_TosState(info.field_type());
 
-  // We need to delay resolving put instructions on final fields
-  // until we actually invoke one. This is required so we throw
-  // exceptions at the correct place. If we do not resolve completely
-  // in the current pass, leaving the put_code set to zero will
-  // cause the next put instruction to reresolve.
-  Bytecodes::Code put_code = (Bytecodes::Code)0;
-
-  // We also need to delay resolving getstatic instructions until the
-  // class is intitialized.  This is required so that access to the static
+  // Put instructions on final fields are not resolved. This is required so we throw
+  // exceptions at the correct place (when the instruction is actually invoked).
+  // If we do not resolve an instruction in the current pass, leaving the put_code
+  // set to zero will cause the next put instruction to the same field to reresolve.
+  //
+  // Also, we need to delay resolving getstatic and putstatic instructions until the
+  // class is initialized.  This is required so that access to the static
   // field will call the initialization function every time until the class
   // is completely initialized ala. in 2.17.5 in JVM Specification.
   InstanceKlass* klass = InstanceKlass::cast(info.field_holder());
   bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) &&
                                !klass->is_initialized());
+
+  Bytecodes::Code put_code = (Bytecodes::Code)0;
+  if (is_put && !info.access_flags().is_final() && !uninitialized_static) {
+    put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
+  }
+
   Bytecodes::Code get_code = (Bytecodes::Code)0;
-
   if (!uninitialized_static) {
     get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);
-    if (is_put || !info.access_flags().is_final()) {
-      put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
-    }
   }
 
   cp_cache_entry->set_field(
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -970,7 +970,7 @@
       if (is_initialized_static_final_update || is_initialized_instance_final_update) {
         ss.print("Update to %s final field %s.%s attempted from a different method (%s) than the initializer method %s ",
                  is_static ? "static" : "non-static", resolved_klass()->external_name(), fd.name()->as_C_string(),
-                 current_klass()->external_name(),
+                 m()->name()->as_C_string(),
                  is_static ? "<clinit>" : "<init>");
         THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string());
       }
--- a/hotspot/src/share/vm/logging/logConfiguration.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/logging/logConfiguration.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -415,17 +415,8 @@
 void LogConfiguration::describe_current_configuration(outputStream* out){
   out->print_cr("Log output configuration:");
   for (size_t i = 0; i < _n_outputs; i++) {
-    out->print("#" SIZE_FORMAT ": %s ", i, _outputs[i]->name());
-    out->print_raw(_outputs[i]->config_string());
-    out->print(" ");
-    char delimiter[2] = {0};
-    for (size_t d = 0; d < LogDecorators::Count; d++) {
-      LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
-      if (_outputs[i]->decorators().is_decorator(decorator)) {
-        out->print("%s%s", delimiter, LogDecorators::name(decorator));
-        *delimiter = ',';
-      }
-    }
+    out->print("#" SIZE_FORMAT ": ", i);
+    _outputs[i]->describe(out);
     out->cr();
   }
 }
--- a/hotspot/src/share/vm/logging/logFileOutput.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/logging/logFileOutput.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -428,3 +428,13 @@
   result[result_len] = '\0';
   return result;
 }
+
+void LogFileOutput::describe(outputStream *out) {
+  LogOutput::describe(out);
+  out->print(" ");
+
+  out->print("filecount=%u,filesize=" SIZE_FORMAT "%s", _file_count,
+             byte_size_in_proper_unit(_rotate_size),
+             proper_unit_for_byte_size(_rotate_size));
+}
+
--- a/hotspot/src/share/vm/logging/logFileOutput.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/logging/logFileOutput.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -85,6 +85,7 @@
   virtual int write(const LogDecorations& decorations, const char* msg);
   virtual int write(LogMessageBuffer::Iterator msg_iterator);
   virtual void force_rotate();
+  virtual void describe(outputStream *out);
 
   virtual const char* name() const {
     return _name;
--- a/hotspot/src/share/vm/logging/logOutput.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/logging/logOutput.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -83,3 +83,18 @@
     break;
   }
 }
+
+void LogOutput::describe(outputStream *out) {
+  out->print("%s ", name());
+  out->print_raw(config_string());
+  out->print(" ");
+  char delimiter[2] = {0};
+  for (size_t d = 0; d < LogDecorators::Count; d++) {
+    LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
+    if (decorators().is_decorator(decorator)) {
+      out->print("%s%s", delimiter, LogDecorators::name(decorator));
+      *delimiter = ',';
+    }
+  }
+}
+
--- a/hotspot/src/share/vm/logging/logOutput.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/logging/logOutput.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -83,6 +83,8 @@
     // Do nothing by default.
   }
 
+  virtual void describe(outputStream *out);
+
   virtual const char* name() const = 0;
   virtual bool initialize(const char* options, outputStream* errstream) = 0;
   virtual int write(const LogDecorations& decorations, const char* msg) = 0;
--- a/hotspot/src/share/vm/logging/logPrefix.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/logging/logPrefix.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -74,6 +74,7 @@
   LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref)) \
   LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref, start)) \
   LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, start)) \
+  LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, stringtable)) \
   LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, sweep)) \
   LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task)) \
   LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, start)) \
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -3106,10 +3106,6 @@
 
   assert(MetaspaceSize <= MaxMetaspaceSize, "MetaspaceSize should be limited by MaxMetaspaceSize");
 
-  if (MetaspaceSize < 256*K) {
-    vm_exit_during_initialization("Too small initial Metaspace size");
-  }
-
   MinMetaspaceExpansion = align_size_down_bounded(MinMetaspaceExpansion, _commit_alignment);
   MaxMetaspaceExpansion = align_size_down_bounded(MaxMetaspaceExpansion, _commit_alignment);
 
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -60,6 +60,7 @@
 bool MetaspaceShared::_check_classes_made_progress;
 bool MetaspaceShared::_has_error_classes;
 bool MetaspaceShared::_archive_loading_failed = false;
+bool MetaspaceShared::_remapped_readwrite = false;
 address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL;
 size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
 SharedMiscRegion MetaspaceShared::_mc;
@@ -806,6 +807,10 @@
       exit(1);
     }
   }
+
+  // Copy the verification constraints from C_HEAP-alloced GrowableArrays to RO-alloced
+  // Arrays
+  SystemDictionaryShared::finalize_verification_constraints();
 }
 
 void MetaspaceShared::prepare_for_dumping() {
@@ -1181,6 +1186,7 @@
     if (!mapinfo->remap_shared_readonly_as_readwrite()) {
       return false;
     }
+    _remapped_readwrite = true;
   }
   return true;
 }
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -125,6 +125,7 @@
   static bool _check_classes_made_progress;
   static bool _has_error_classes;
   static bool _archive_loading_failed;
+  static bool _remapped_readwrite;
   static address _cds_i2i_entry_code_buffers;
   static size_t  _cds_i2i_entry_code_buffers_size;
 
@@ -205,6 +206,10 @@
   // sharing is enabled. Simply returns true if sharing is not enabled
   // or if the remapping has already been done by a prior call.
   static bool remap_shared_readonly_as_readwrite() NOT_CDS_RETURN_(true);
+  static bool remapped_readwrite() {
+    CDS_ONLY(return _remapped_readwrite);
+    NOT_CDS(return false);
+  }
 
   static void print_shared_spaces();
 
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -27,6 +27,7 @@
 #include "classfile/classFileStream.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/systemDictionary.hpp"
+#include "classfile/systemDictionaryShared.hpp"
 #include "classfile/verifier.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/dependencyContext.hpp"
@@ -597,6 +598,8 @@
 
         // also sets rewritten
         this_k->rewrite_class(CHECK_false);
+      } else if (this_k->is_shared()) {
+        SystemDictionaryShared::check_verification_constraints(this_k, CHECK_false);
       }
 
       // relocate jsrs and link methods after they are all rewritten
@@ -606,7 +609,12 @@
       // methods have been rewritten since rewrite may
       // fabricate new Method*s.
       // also does loader constraint checking
-      if (!this_k()->is_shared()) {
+      //
+      // initialize_vtable and initialize_itable need to be rerun for
+      // a shared class if the class is not loaded by the NULL classloader.
+      ClassLoaderData * loader_data = this_k->class_loader_data();
+      if (!(this_k->is_shared() &&
+            loader_data->is_the_null_class_loader_data())) {
         ResourceMark rm(THREAD);
         this_k->vtable()->initialize_vtable(true, CHECK_false);
         this_k->itable()->initialize_itable(true, CHECK_false);
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,13 +50,12 @@
   // Query before forming handle.
   int size = instance_size(k);
   KlassHandle h_k(THREAD, this);
-  instanceOop i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
+
+  assert(size > 0, "total object size must be positive: %d", size);
 
   // Since mirrors can be variable sized because of the static fields, store
   // the size in the mirror itself.
-  java_lang_Class::set_oop_size(i, size);
-
-  return i;
+  return (instanceOop)CollectedHeap::class_allocate(h_k, size, CHECK_NULL);
 }
 
 int InstanceMirrorKlass::oop_size(oop obj) const {
--- a/hotspot/src/share/vm/oops/klassVtable.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -27,6 +27,7 @@
 #include "classfile/vmSymbols.hpp"
 #include "gc/shared/gcLocker.hpp"
 #include "logging/log.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
 #include "oops/instanceKlass.hpp"
@@ -42,6 +43,10 @@
   return InstanceKlass::cast(_klass());
 }
 
+bool klassVtable::is_preinitialized_vtable() {
+  return _klass->is_shared() && !MetaspaceShared::remapped_readwrite();
+}
+
 
 // this function computes the vtable size (including the size needed for miranda
 // methods) and the number of miranda methods in this class.
@@ -126,6 +131,12 @@
 int klassVtable::initialize_from_super(KlassHandle super) {
   if (super.is_null()) {
     return 0;
+  } else if (is_preinitialized_vtable()) {
+    // A shared class' vtable is preinitialized at dump time. No need to copy
+    // methods from super class for shared class, as that was already done
+    // during archiving time. However, if Jvmti has redefined a class,
+    // copy super class's vtable in case the super class has changed.
+    return super->vtable()->length();
   } else {
     // copy methods from superKlass
     klassVtable* superVtable = super->vtable();
@@ -152,6 +163,8 @@
   KlassHandle super (THREAD, klass()->java_super());
   int nofNewEntries = 0;
 
+  bool is_shared = _klass->is_shared();
+
   if (!klass()->is_array_klass()) {
     ResourceMark rm(THREAD);
     log_develop_debug(vtables)("Initializing: %s", _klass->name()->as_C_string());
@@ -164,6 +177,7 @@
 #endif
 
   if (Universe::is_bootstrapping()) {
+    assert(!is_shared, "sanity");
     // just clear everything
     for (int i = 0; i < _length; i++) table()[i].clear();
     return;
@@ -203,6 +217,7 @@
       if (len > 0) {
         Array<int>* def_vtable_indices = NULL;
         if ((def_vtable_indices = ik()->default_vtable_indices()) == NULL) {
+          assert(!is_shared, "shared class def_vtable_indices does not exist");
           def_vtable_indices = ik()->create_new_default_vtable_indices(len, CHECK);
         } else {
           assert(def_vtable_indices->length() == len, "reinit vtable len?");
@@ -217,7 +232,15 @@
           // needs new entry
           if (needs_new_entry) {
             put_method_at(mh(), initialized);
-            def_vtable_indices->at_put(i, initialized); //set vtable index
+            if (is_preinitialized_vtable()) {
+              // At runtime initialize_vtable is rerun for a shared class
+              // (loaded by the non-boot loader) as part of link_class_impl().
+              // The dumptime vtable index should be the same as the runtime index.
+              assert(def_vtable_indices->at(i) == initialized,
+                     "dump time vtable index is different from runtime index");
+            } else {
+              def_vtable_indices->at_put(i, initialized); //set vtable index
+            }
             initialized++;
           }
         }
@@ -378,7 +401,8 @@
   }
 
   // we need a new entry if there is no superclass
-  if (klass->super() == NULL) {
+  Klass* super = klass->super();
+  if (super == NULL) {
     return allocate_new;
   }
 
@@ -407,7 +431,15 @@
 
   Symbol* target_classname = target_klass->name();
   for(int i = 0; i < super_vtable_len; i++) {
-    Method* super_method = method_at(i);
+    Method* super_method;
+    if (is_preinitialized_vtable()) {
+      // If this is a shared class, the vtable is already in the final state (fully
+      // initialized). Need to look at the super's vtable.
+      klassVtable* superVtable = super->vtable();
+      super_method = superVtable->method_at(i);
+    } else {
+      super_method = method_at(i);
+    }
     // Check if method name matches
     if (super_method->name() == name && super_method->signature() == signature) {
 
@@ -475,7 +507,15 @@
           target_method()->set_vtable_index(i);
         } else {
           if (def_vtable_indices != NULL) {
-            def_vtable_indices->at_put(default_index, i);
+            if (is_preinitialized_vtable()) {
+              // At runtime initialize_vtable is rerun as part of link_class_impl()
+              // for a shared class loaded by the non-boot loader.
+              // The dumptime vtable index should be the same as the runtime index.
+              assert(def_vtable_indices->at(default_index) == i,
+                     "dump time vtable index is different from runtime index");
+            } else {
+              def_vtable_indices->at_put(default_index, i);
+            }
           }
           assert(super_method->is_default_method() || super_method->is_overpass()
                  || super_method->is_abstract(), "default override error");
@@ -490,17 +530,26 @@
 }
 
 void klassVtable::put_method_at(Method* m, int index) {
-  if (log_develop_is_enabled(Trace, vtables)) {
-    ResourceMark rm;
-    outputStream* logst = Log(vtables)::trace_stream();
-    const char* sig = (m != NULL) ? m->name_and_sig_as_C_string() : "<NULL>";
-    logst->print("adding %s at index %d, flags: ", sig, index);
-    if (m != NULL) {
-      m->print_linkage_flags(logst);
+  if (is_preinitialized_vtable()) {
+    // At runtime initialize_vtable is rerun as part of link_class_impl()
+    // for shared class loaded by the non-boot loader to obtain the loader
+    // constraints based on the runtime classloaders' context. The dumptime
+    // method at the vtable index should be the same as the runtime method.
+    assert(table()[index].method() == m,
+           "archived method is different from the runtime method");
+  } else {
+    if (log_develop_is_enabled(Trace, vtables)) {
+      ResourceMark rm;
+      outputStream* logst = Log(vtables)::trace_stream();
+      const char* sig = (m != NULL) ? m->name_and_sig_as_C_string() : "<NULL>";
+      logst->print("adding %s at index %d, flags: ", sig, index);
+      if (m != NULL) {
+        m->print_linkage_flags(logst);
+      }
+      logst->cr();
     }
-    logst->cr();
+    table()[index].set(m);
   }
-  table()[index].set(m);
 }
 
 // Find out if a method "m" with superclass "super", loader "classloader" and
@@ -950,7 +999,15 @@
 void itableMethodEntry::initialize(Method* m) {
   if (m == NULL) return;
 
-  _method = m;
+  if (MetaspaceShared::is_in_shared_space((void*)&_method) &&
+     !MetaspaceShared::remapped_readwrite()) {
+    // At runtime initialize_itable is rerun as part of link_class_impl()
+    // for a shared class loaded by the non-boot loader.
+    // The dumptime itable method entry should be the same as the runtime entry.
+    assert(_method == m, "sanity");
+  } else {
+    _method = m;
+  }
 }
 
 klassItable::klassItable(instanceKlassHandle klass) {
@@ -1054,7 +1111,11 @@
         logst->cr();
       }
       if (!m->has_vtable_index()) {
-        assert(m->vtable_index() == Method::pending_itable_index, "set by initialize_vtable");
+        // A shared method could have an initialized itable_index that
+        // is < 0.
+        assert(m->vtable_index() == Method::pending_itable_index ||
+               m->is_shared(),
+               "set by initialize_vtable");
         m->set_itable_index(ime_num);
         // Progress to next itable entry
         ime_num++;
@@ -1248,7 +1309,6 @@
 }
 #endif // INCLUDE_JVMTI
 
-
 // Setup
 class InterfaceVisiterClosure : public StackObj {
  public:
--- a/hotspot/src/share/vm/oops/klassVtable.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/oops/klassVtable.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -153,6 +153,19 @@
       Array<Klass*>* local_interfaces);
   void verify_against(outputStream* st, klassVtable* vt, int index);
   inline InstanceKlass* ik() const;
+  // When loading a class from CDS archive at run time, and no class redefintion
+  // has happened, it is expected that the class's itable/vtables are
+  // laid out exactly the same way as they had been during dump time.
+  // Therefore, in klassVtable::initialize_[iv]table, we do not layout the
+  // tables again. Instead, we only rerun the process to create/check
+  // the class loader constraints. In non-product builds, we add asserts to
+  // guarantee that the table's layout would be the same as at dump time.
+  //
+  // If JVMTI redefines any class, the read-only shared memory are remapped
+  // as read-write. A shared class' vtable/itable are re-initialized and
+  // might have different layout due to class redefinition of the shared class
+  // or its super types.
+  bool is_preinitialized_vtable();
 };
 
 
--- a/hotspot/src/share/vm/oops/method.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/oops/method.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -313,6 +313,33 @@
   unlink_method();
 }
 
+void Method::set_vtable_index(int index) {
+  if (is_shared() && !MetaspaceShared::remapped_readwrite()) {
+    // At runtime initialize_vtable is rerun as part of link_class_impl()
+    // for a shared class loaded by the non-boot loader to obtain the loader
+    // constraints based on the runtime classloaders' context.
+    return; // don't write into the shared class
+  } else {
+    _vtable_index = index;
+  }
+}
+
+void Method::set_itable_index(int index) {
+  if (is_shared() && !MetaspaceShared::remapped_readwrite()) {
+    // At runtime initialize_itable is rerun as part of link_class_impl()
+    // for a shared class loaded by the non-boot loader to obtain the loader
+    // constraints based on the runtime classloaders' context. The dumptime
+    // itable index should be the same as the runtime index.
+    assert(_vtable_index == itable_index_max - index,
+           "archived itable index is different from runtime index");
+    return; // don’t write into the shared class
+  } else {
+    _vtable_index = itable_index_max - index;
+  }
+  assert(valid_itable_index(), "");
+}
+
+
 
 bool Method::was_executed_more_than(int n) {
   // Invocation counter is reset when the Method* is compiled.
--- a/hotspot/src/share/vm/oops/method.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/oops/method.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -470,12 +470,12 @@
   DEBUG_ONLY(bool valid_vtable_index() const     { return _vtable_index >= nonvirtual_vtable_index; })
   bool has_vtable_index() const                  { return _vtable_index >= 0; }
   int  vtable_index() const                      { return _vtable_index; }
-  void set_vtable_index(int index)               { _vtable_index = index; }
+  void set_vtable_index(int index);
   DEBUG_ONLY(bool valid_itable_index() const     { return _vtable_index <= pending_itable_index; })
   bool has_itable_index() const                  { return _vtable_index <= itable_index_max; }
   int  itable_index() const                      { assert(valid_itable_index(), "");
                                                    return itable_index_max - _vtable_index; }
-  void set_itable_index(int index)               { _vtable_index = itable_index_max - index; assert(valid_itable_index(), ""); }
+  void set_itable_index(int index);
 
   // interpreter entry
   address interpreter_entry() const              { return _i2i_entry; }
--- a/hotspot/src/share/vm/oops/oop.inline.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -258,8 +258,8 @@
     }
   }
 
-  assert(s % MinObjAlignment == 0, "alignment check");
-  assert(s > 0, "Bad size calculated");
+  assert(s % MinObjAlignment == 0, "Oop size is not properly aligned: %d", s);
+  assert(s > 0, "Oop size must be greater than zero, not %d", s);
   return s;
 }
 
--- a/hotspot/src/share/vm/opto/library_call.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -2405,8 +2405,13 @@
   Compile::AliasType* alias_type = C->alias_type(adr_type);
   assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here");
 
-  assert(alias_type->adr_type() == TypeRawPtr::BOTTOM || alias_type->adr_type() == TypeOopPtr::BOTTOM ||
-         alias_type->basic_type() != T_ILLEGAL, "field, array element or unknown");
+  // Only field, array element or unknown locations are supported.
+  if (alias_type->adr_type() != TypeRawPtr::BOTTOM &&
+      alias_type->adr_type() != TypeOopPtr::BOTTOM &&
+      alias_type->basic_type() == T_ILLEGAL) {
+    return false;
+  }
+
   bool mismatched = false;
   BasicType bt = alias_type->basic_type();
   if (bt != T_ILLEGAL) {
@@ -2782,12 +2787,6 @@
       ShouldNotReachHere();
   }
 
-  // Null check receiver.
-  receiver = null_check(receiver);
-  if (stopped()) {
-    return true;
-  }
-
   // Build field offset expression.
   // We currently rely on the cookies produced by Unsafe.xxxFieldOffset
   // to be plain byte offsets, which are also the same as those accepted
@@ -2799,8 +2798,6 @@
   const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
 
   Compile::AliasType* alias_type = C->alias_type(adr_type);
-  assert(alias_type->adr_type() == TypeRawPtr::BOTTOM || alias_type->adr_type() == TypeOopPtr::BOTTOM ||
-         alias_type->basic_type() != T_ILLEGAL, "field, array element or unknown");
   BasicType bt = alias_type->basic_type();
   if (bt != T_ILLEGAL &&
       ((bt == T_OBJECT || bt == T_ARRAY) != (type == T_OBJECT))) {
@@ -2832,6 +2829,12 @@
       ShouldNotReachHere();
   }
 
+  // Null check receiver.
+  receiver = null_check(receiver);
+  if (stopped()) {
+    return true;
+  }
+
   int alias_idx = C->get_alias_index(adr_type);
 
   // Memory-model-wise, a LoadStore acts like a little synchronized
--- a/hotspot/src/share/vm/prims/jvmti.xml	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/prims/jvmti.xml	Wed Jul 05 22:00:06 2017 +0200
@@ -6509,6 +6509,59 @@
       <errors>
       </errors>
     </function>
+
+    <function id="GetNamedModule" num="40" since="9">
+      <synopsis>Get Named Module</synopsis>
+      <description>
+        Return the <code>java.lang.reflect.Module</code> object for a named
+        module defined to a class loader that contains a given package.
+        The module is returned via <code>module_ptr</code>.
+        <p/>
+        If a named module is defined to the class loader and it
+        contains the package then that named module is returned,
+        otherwise <code>NULL</code> is returned.
+        <p/>
+      </description>
+      <origin>new</origin>
+      <capabilities>
+      </capabilities>
+      <parameters>
+        <param id="class_loader">
+          <ptrtype>
+            <jobject/>
+            <nullok>the bootstrap loader is assumed</nullok>
+          </ptrtype>
+          <description>
+            A class loader.
+            If the <code>class_loader</code> is not <code>NULL</code>
+            or a subclass of <code>java.lang.ClassLoader</code>
+            this function returns
+            <errorlink id="JVMTI_ERROR_ILLEGAL_ARGUMENT"></errorlink>.
+          </description>
+        </param>
+        <param id="package_name">
+          <inbuf><char/></inbuf>
+          <description>
+            The name of the package, encoded as a
+            <internallink id="mUTF">modified UTF-8</internallink> string.
+            The package name is in internal form (JVMS 4.2.1);
+            identifiers are separated by forward slashes rather than periods.
+          </description>
+        </param>
+        <param id="module_ptr">
+          <outptr><jobject/></outptr>
+          <description>
+            On return, points to a <code>java.lang.reflect.Module</code> object
+            or points to <code>NULL</code>.
+          </description>
+        </param>
+      </parameters>
+      <errors>
+        <error id="JVMTI_ERROR_ILLEGAL_ARGUMENT">
+          If class loader is not <code>NULL</code> and is not a class loader object.
+        </error>
+      </errors>
+    </function>
   </category>
 
   <category id="class" label="Class">
@@ -12462,6 +12515,14 @@
     <code>new_class_data</code> has been set, it becomes the 
     <code>class_data</code> for the next agent.
     <p/>
+    When handling a class load in the live phase, then the
+    <functionlink id="GetNamedModule"></functionlink>
+    function can be used to map class loader and a package name to a module.
+    When a class is being redefined or retransformed then
+    <code>class_being_redefined</code> is non <code>NULL</code> and so
+    the JNI <code>GetModule</code> function can also be used
+    to obtain the Module.
+    <p/>
     The order that this event is sent to each environment differs
     from other events.
     This event is sent to environments in the following order:
@@ -14427,20 +14488,15 @@
   <change date="19 June 2013" version="1.2.3">
       Added support for statically linked agents.
   </change>
-  <change date="20 January 2016" version="9.0.0">
+  <change date="5 July 2016" version="9.0.0">
       Support for modules:
        - The majorversion is 9 now
        - The ClassFileLoadHook events are not sent during the primordial phase anymore.
        - Add new function GetAllModules
-  </change>
-  <change date="17 February 2016" version="9.0.0">
-      Support for modules:
        - Add new capability can_generate_early_vmstart
        - Allow CompiledMethodLoad events at start phase
-  </change>
-  <change date="14 April 2016" version="9.0.0">
-      Support for modules:
        - Add new capability can_generate_early_class_hook_events
+       - Add new function GetNamedModule
   </change>
 </changehistory>
 
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/classLoaderExt.hpp"
+#include "classfile/modules.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "interpreter/bytecodeStream.hpp"
@@ -201,6 +202,28 @@
 } /* end GetAllModules */
 
 
+// class_loader - NULL is a valid value, must be pre-checked
+// package_name - pre-checked for NULL
+// module_ptr - pre-checked for NULL
+jvmtiError
+JvmtiEnv::GetNamedModule(jobject class_loader, const char* package_name, jobject* module_ptr) {
+  JavaThread* THREAD = JavaThread::current(); // pass to macros
+  ResourceMark rm(THREAD);
+
+  Handle h_loader (THREAD, JNIHandles::resolve(class_loader));
+  // Check that loader is a subclass of java.lang.ClassLoader.
+  if (h_loader.not_null() && !java_lang_ClassLoader::is_subclass(h_loader->klass())) {
+    return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+  }
+  jobject module = Modules::get_named_module(h_loader, package_name, THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    CLEAR_PENDING_EXCEPTION;
+    return JVMTI_ERROR_INTERNAL; // unexpected exception
+  }
+  *module_ptr = module;
+  return JVMTI_ERROR_NONE;
+} /* end GetNamedModule */
+
   //
   // Class functions
   //
--- a/hotspot/src/share/vm/runtime/objectMonitor.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -131,8 +131,6 @@
 static int Knob_QMode               = 0;       // EntryList-cxq policy - queue discipline
 static volatile int InitDone        = 0;
 
-#define TrySpin TrySpin_VaryDuration
-
 // -----------------------------------------------------------------------------
 // Theory of operations -- Monitors lists, thread residency, etc:
 //
@@ -1848,13 +1846,8 @@
 // hysteresis control to damp the transition rate between spinning and
 // not spinning.
 
-intptr_t ObjectMonitor::SpinCallbackArgument = 0;
-int (*ObjectMonitor::SpinCallbackFunction)(intptr_t, int) = NULL;
-
 // Spinning: Fixed frequency (100%), vary duration
-
-
-int ObjectMonitor::TrySpin_VaryDuration(Thread * Self) {
+int ObjectMonitor::TrySpin(Thread * Self) {
   // Dumb, brutal spin.  Good for comparative measurements against adaptive spinning.
   int ctr = Knob_FixedSpin;
   if (ctr != 0) {
@@ -1948,11 +1941,6 @@
         goto Abort;           // abrupt spin egress
       }
       if (Knob_UsePause & 1) SpinPause();
-
-      int (*scb)(intptr_t,int) = SpinCallbackFunction;
-      if (hits > 50 && scb != NULL) {
-        int abend = (*scb)(SpinCallbackArgument, 0);
-      }
     }
 
     if (Knob_UsePause & 2) SpinPause();
--- a/hotspot/src/share/vm/runtime/objectMonitor.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/runtime/objectMonitor.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -161,9 +161,6 @@
   Thread * volatile _Responsible;
 
   volatile int _Spinner;            // for exit->spinner handoff optimization
-  volatile int _SpinFreq;           // Spin 1-out-of-N attempts: success rate
-  volatile int _SpinClock;
-  volatile intptr_t _SpinState;     // MCS/CLH list of spinners
   volatile int _SpinDuration;
 
   volatile jint  _count;            // reference count to prevent reclamation/deflation
@@ -238,10 +235,6 @@
   static int cxq_offset_in_bytes()         { return offset_of(ObjectMonitor, _cxq); }
   static int succ_offset_in_bytes()        { return offset_of(ObjectMonitor, _succ); }
   static int EntryList_offset_in_bytes()   { return offset_of(ObjectMonitor, _EntryList); }
-  static int FreeNext_offset_in_bytes()    { return offset_of(ObjectMonitor, FreeNext); }
-  static int WaitSet_offset_in_bytes()     { return offset_of(ObjectMonitor, _WaitSet); }
-  static int Responsible_offset_in_bytes() { return offset_of(ObjectMonitor, _Responsible); }
-  static int Spinner_offset_in_bytes()     { return offset_of(ObjectMonitor, _Spinner); }
 
   // ObjectMonitor references can be ORed with markOopDesc::monitor_value
   // as part of the ObjectMonitor tagging mechanism. When we combine an
@@ -257,11 +250,6 @@
   #define OM_OFFSET_NO_MONITOR_VALUE_TAG(f) \
     ((ObjectMonitor::f ## _offset_in_bytes()) - markOopDesc::monitor_value)
 
-  // Eventually we'll make provisions for multiple callbacks, but
-  // now one will suffice.
-  static int (*SpinCallbackFunction)(intptr_t, int);
-  static intptr_t SpinCallbackArgument;
-
   markOop   header() const;
   void      set_header(markOop hdr);
 
@@ -312,8 +300,6 @@
     _cxq           = NULL;
     _WaitSet       = NULL;
     _recursions    = 0;
-    _SpinFreq      = 0;
-    _SpinClock     = 0;
   }
 
  public:
@@ -353,9 +339,7 @@
   void      UnlinkAfterAcquire(Thread * Self, ObjectWaiter * SelfNode);
   int       TryLock(Thread * Self);
   int       NotRunnable(Thread * Self, Thread * Owner);
-  int       TrySpin_Fixed(Thread * Self);
-  int       TrySpin_VaryFrequency(Thread * Self);
-  int       TrySpin_VaryDuration(Thread * Self);
+  int       TrySpin(Thread * Self);
   void      ExitEpilog(Thread * Self, ObjectWaiter * Wakee);
   bool      ExitSuspendEquivalent(JavaThread * Self);
   void      post_monitor_wait_event(EventJavaMonitorWait * event,
--- a/hotspot/src/share/vm/runtime/synchronizer.hpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/src/share/vm/runtime/synchronizer.hpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -144,8 +144,6 @@
   static void verify() PRODUCT_RETURN;
   static int  verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
 
-  static void RegisterSpinCallback(int(*)(intptr_t, int), intptr_t);
-
  private:
   enum { _BLOCKSIZE = 128 };
   // global list of blocks of monitors
--- a/hotspot/test/compiler/ciReplay/TestVM_no_comp_level.sh	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/compiler/ciReplay/TestVM_no_comp_level.sh	Wed Jul 05 22:00:06 2017 +0200
@@ -29,6 +29,7 @@
 ## @summary testing of ciReplay with using generated by VM replay.txt w/o comp_level
 ## @author igor.ignatyev@oracle.com
 ## @requires vm.flightRecorder != true
+## @ignore 8157984
 ## @run shell TestVM_no_comp_level.sh
 ##
 
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java	Wed Jul 05 22:00:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
  * @library ../../../../../
+ * @ignore 8161550
  * @modules java.base/jdk.internal.reflect
  *          jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
--- a/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java	Wed Jul 05 22:00:06 2017 +0200
@@ -28,6 +28,7 @@
  * @library /testlibrary /test/lib /
  * @modules java.base/jdk.internal.misc
  *          java.management
+ * @ignore 8157984
  * @build TestRangeCheckSmearing
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                jdk.test.lib.Platform
--- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -26,6 +26,7 @@
  * @library /testlibrary /test/lib /
  * @modules java.base/jdk.internal.misc
  * @modules java.management
+ * @ignore 8157984
  * @build NonTieredLevelsTest
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/unsafe/OpaqueAccesses.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8155781
+ * @modules java.base/jdk.internal.misc
+ *
+ * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
+ *                                 -XX:-TieredCompilation -Xbatch
+ *                                 -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*
+ *                                 compiler.unsafe.OpaqueAccesses
+ */
+package compiler.unsafe;
+
+import jdk.internal.misc.Unsafe;
+
+import java.lang.reflect.Field;
+
+public class OpaqueAccesses {
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+    private static final Object INSTANCE = new OpaqueAccesses();
+
+    private static final Object[] ARRAY = new Object[10];
+
+    private static final long F_OFFSET;
+    private static final long E_OFFSET;
+
+    static {
+        try {
+            Field field = OpaqueAccesses.class.getDeclaredField("f");
+            F_OFFSET = UNSAFE.objectFieldOffset(field);
+
+            E_OFFSET = UNSAFE.arrayBaseOffset(ARRAY.getClass());
+        } catch (NoSuchFieldException e) {
+            throw new Error(e);
+        }
+    }
+
+    private Object f = new Object();
+
+    static Object testFixedOffsetField(Object o) {
+        return UNSAFE.getObject(o, F_OFFSET);
+    }
+
+    static int testFixedOffsetHeader0(Object o) {
+        return UNSAFE.getInt(o, 0);
+    }
+
+    static int testFixedOffsetHeader4(Object o) {
+        return UNSAFE.getInt(o, 4);
+    }
+
+    static Object testFixedBase(long off) {
+        return UNSAFE.getObject(INSTANCE, off);
+    }
+
+    static Object testOpaque(Object o, long off) {
+        return UNSAFE.getObject(o, off);
+    }
+
+    static int testFixedOffsetHeaderArray0(Object[] arr) {
+        return UNSAFE.getInt(arr, 0);
+    }
+
+    static int testFixedOffsetHeaderArray4(Object[] arr) {
+        return UNSAFE.getInt(arr, 4);
+    }
+
+    static Object testFixedOffsetArray(Object[] arr) {
+        return UNSAFE.getObject(arr, E_OFFSET);
+    }
+
+    static Object testFixedBaseArray(long off) {
+        return UNSAFE.getObject(ARRAY, off);
+    }
+
+    static Object testOpaqueArray(Object[] o, long off) {
+        return UNSAFE.getObject(o, off);
+    }
+
+    static final long ADDR = UNSAFE.allocateMemory(10);
+    static boolean flag;
+
+    static int testMixedAccess() {
+        flag = !flag;
+        Object o = (flag ? INSTANCE : null);
+        long off = (flag ? F_OFFSET : ADDR);
+        return UNSAFE.getInt(o, off);
+    }
+
+    public static void main(String[] args) {
+        for (int i = 0; i < 20_000; i++) {
+            // Instance
+            testFixedOffsetField(INSTANCE);
+            testFixedOffsetHeader0(INSTANCE);
+            testFixedOffsetHeader4(INSTANCE);
+            testFixedBase(F_OFFSET);
+            testOpaque(INSTANCE, F_OFFSET);
+            testMixedAccess();
+
+            // Array
+            testFixedOffsetHeaderArray0(ARRAY);
+            testFixedOffsetHeaderArray4(ARRAY);
+            testFixedOffsetArray(ARRAY);
+            testFixedBaseArray(E_OFFSET);
+            testOpaqueArray(ARRAY, E_OFFSET);
+        }
+        System.out.println("TEST PASSED");
+    }
+}
--- a/hotspot/test/gc/TestSmallHeap.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/gc/TestSmallHeap.java	Wed Jul 05 22:00:06 2017 +0200
@@ -27,6 +27,7 @@
  * @requires vm.gc=="null"
  * @summary Verify that starting the VM with a small heap works
  * @library /testlibrary /test/lib /test/lib/share/classes
+ * @ignore 8161552
  * @modules java.base/jdk.internal.misc
  * @modules java.management/sun.management
  * @build TestSmallHeap
--- a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java	Wed Jul 05 22:00:06 2017 +0200
@@ -29,6 +29,7 @@
  * parallel collectors.
  * @requires vm.gc=="null"
  * @library /testlibrary /test/lib
+ * @ignore 8161552
  * @modules java.base/jdk.internal.misc
  *          java.management
  * @build TestParallelHeapSizeFlags TestMaxHeapSizeTools
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/ergonomics/TestInitialGCThreadLogging.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestInitialGCThreadLogging
+ * @bug 8157240
+ * @summary Check trace logging of initial GC threads.
+ * @requires vm.gc=="null"
+ * @key gc
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ */
+
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+
+public class TestInitialGCThreadLogging {
+  public static void main(String[] args) throws Exception {
+
+    testInitialGCThreadLogging("UseConcMarkSweepGC", "GC Thread");
+
+    testInitialGCThreadLogging("UseG1GC", "GC Thread");
+
+    testInitialGCThreadLogging("UseParallelGC", "ParGC Thread");
+  }
+
+  private static void verifyDynamicNumberOfGCThreads(OutputAnalyzer output, String threadName) {
+    output.shouldHaveExitValue(0); // test should run succesfully
+    output.shouldContain(threadName);
+  }
+
+  private static void testInitialGCThreadLogging(String gcFlag, String threadName) throws Exception {
+    // UseDynamicNumberOfGCThreads and TraceDynamicGCThreads enabled
+    String[] baseArgs = {"-XX:+" + gcFlag, "-Xmx10M", "-XX:+UseDynamicNumberOfGCThreads", "-Xlog:gc+task=trace", "-version"};
+
+    // Base test with gc and +UseDynamicNumberOfGCThreads:
+    ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder(baseArgs);
+    verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start()), threadName);
+  }
+}
--- a/hotspot/test/gc/g1/TestStringSymbolTableStats.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/gc/g1/TestStringSymbolTableStats.java	Wed Jul 05 22:00:06 2017 +0200
@@ -46,7 +46,7 @@
 
     System.out.println("Output:\n" + output.getOutput());
 
-    output.shouldContain("Cleaned string and symbol table");
+    output.shouldMatch("GC\\(\\d+\\) Cleaned string and symbol table");
     output.shouldHaveExitValue(0);
   }
 
--- a/hotspot/test/gc/metaspace/TestMetaspaceInitialization.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/gc/metaspace/TestMetaspaceInitialization.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,11 +24,11 @@
 import java.util.ArrayList;
 
 /* @test TestMetaspaceInitialization
- * @bug 8042933
+ * @bug 8024945
  * @summary Tests to initialize metaspace with a very low MetaspaceSize
  * @modules java.base/jdk.internal.misc
  * @library /testlibrary
- * @run main/othervm -XX:MetaspaceSize=2m TestMetaspaceInitialization
+ * @run main/othervm -XX:MetaspaceSize=0 TestMetaspaceInitialization
  */
 public class TestMetaspaceInitialization {
     private class Internal {
--- a/hotspot/test/gc/metaspace/TestMetaspaceSizeFlags.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/gc/metaspace/TestMetaspaceSizeFlags.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,9 +47,6 @@
     // 8024650: MaxMetaspaceSize was adjusted instead of MetaspaceSize.
     testMaxMetaspaceSizeLTMetaspaceSize(MAX_ALIGNMENT, MAX_ALIGNMENT * 2);
     testMaxMetaspaceSizeGTMetaspaceSize(MAX_ALIGNMENT * 2, MAX_ALIGNMENT);
-    testTooSmallInitialMetaspace(0, 0);
-    testTooSmallInitialMetaspace(0, MAX_ALIGNMENT);
-    testTooSmallInitialMetaspace(MAX_ALIGNMENT, 0);
   }
 
   private static void testMaxMetaspaceSizeEQMetaspaceSize(long maxMetaspaceSize, long metaspaceSize) throws Exception {
@@ -73,11 +70,6 @@
     Asserts.assertEQ(mf.metaspaceSize, metaspaceSize);
   }
 
-  private static void testTooSmallInitialMetaspace(long maxMetaspaceSize, long metaspaceSize) throws Exception {
-    OutputAnalyzer output = run(maxMetaspaceSize, metaspaceSize);
-    output.shouldContain("Too small initial Metaspace size");
-  }
-
   private static MetaspaceFlags runAndGetValue(long maxMetaspaceSize, long metaspaceSize) throws Exception {
     OutputAnalyzer output = run(maxMetaspaceSize, metaspaceSize);
     output.shouldNotMatch("Error occurred during initialization of VM\n.*");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Final/TestPutField.jasm	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class TestPutField
+version 53:0
+{
+
+final Field test_field:"I";
+
+
+public Method <init>:"()V"
+       stack 2 locals 1
+{
+	aload_0;
+	dup;
+	invokespecial Method java/lang/Object.<init>:"()V";
+	bipush 13;
+        putfield Field test_field:"I";
+        return;
+}
+
+public Method aMethod:"()I"
+       stack 2 locals 2
+{
+	aload_0;
+	getfield Field test_field:"I";
+	istore_1;
+	aload_0;
+	bipush 14;
+        putfield Field test_field:"I";
+	iload_1;
+        ireturn;
+}
+
+
+public static Method test:"()V"
+       stack 2 locals 2
+{
+	new class TestPutField;
+	astore_0;
+	aload_0;
+	invokespecial Method <init>:"()V";
+	getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
+	astore_1;
+	aload_1;
+	aload_0;
+	invokevirtual Method aMethod:"()I";
+	invokevirtual Method java/io/PrintStream.println:"(I)V";
+	aload_1;
+	aload_0;
+	getfield Field test_field:"I";	
+	invokevirtual Method java/io/PrintStream.println:"(I)V";
+        return;
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Final/TestPutMain.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8160527
+ * @summary The VM does not always perform checks added by 8157181 when updating final instance fields
+ * @library /testlibrary
+ * @compile TestPutField.jasm
+ * @compile TestPutStatic.jasm
+ * @compile TestPutMain.java
+ * @run main/othervm TestPutMain
+ */
+
+import jdk.test.lib.Asserts;
+
+public class TestPutMain {
+    public static void main(String[] args) {
+        boolean exception = false;
+        try {
+            TestPutField.test();
+        } catch (java.lang.IllegalAccessError e) {
+            exception = true;
+        }
+
+        Asserts.assertTrue(exception, "FAILED: Expected IllegalAccessError for illegal update to final instance field was not thrown.");
+
+        exception = false;
+        try {
+            TestPutStatic.test();
+        } catch (java.lang.IllegalAccessError e) {
+            exception = true;
+        }
+
+        Asserts.assertTrue(exception, "FAILED: Expected IllegalAccessError for illegal update to final static field was not thrown.");
+
+        System.out.println("PASSED: Expected IllegalAccessError was thrown.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Final/TestPutStatic.jasm	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class TestPutStatic
+version 53:0
+{
+
+final static Field test_field:"I";
+
+
+public static Method <clinit>:"()V"
+       stack 2 locals 1
+{
+	bipush 13;
+        putstatic Field test_field:"I";
+        return;
+}
+
+public static Method aMethod:"()I"
+       stack 1 locals 1
+{
+	getstatic Field test_field:"I";
+	istore_0;
+	bipush 14;
+        putstatic Field test_field:"I";
+	iload_0;
+        ireturn;
+}
+
+
+public static Method test:"()V"
+       stack 2 locals 1
+{
+	getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
+	astore_0;
+	aload_0;
+	invokestatic Method aMethod:"()I";
+	invokevirtual Method java/io/PrintStream.println:"(I)V";
+	aload_0;
+	getstatic Field test_field:"I";	
+	invokevirtual Method java/io/PrintStream.println:"(I)V";
+        return;
+}
+
+}
--- a/hotspot/test/runtime/SharedArchiveFile/SASymbolTableTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/runtime/SharedArchiveFile/SASymbolTableTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -24,6 +24,9 @@
 /*
  * @test SASymbolTableTest
  * @summary Walk symbol table using SA, with and without CDS.
+ * Started failing on 2016.06.24 due to 8160376 on MacOS X so quarantine
+ * it on that platform:
+ * @requires os.family != "mac"
  * @library /testlibrary
  * @modules java.base/jdk.internal.misc
  *          jdk.hotspot.agent/sun.jvm.hotspot.oops
--- a/hotspot/test/runtime/Unsafe/GetUnsafe.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/runtime/Unsafe/GetUnsafe.java	Wed Jul 05 22:00:06 2017 +0200
@@ -26,6 +26,7 @@
  * @summary Verifies that getUnsafe() actually throws SecurityException when unsafeAccess is prohibited.
  * @library /testlibrary
  * @modules java.base/jdk.internal.misc
+ * @ignore 8161947
  * @run main GetUnsafe
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/GetNamedModule/MyPackage/GetNamedModuleTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package MyPackage;
+
+/**
+ * @test
+ * @summary Verifies the JVMTI GetNamedModule API
+ * @compile GetNamedModuleTest.java
+ * @run main/othervm/native -agentlib:GetNamedModuleTest MyPackage.GetNamedModuleTest
+ */
+
+import java.io.PrintStream;
+
+public class GetNamedModuleTest {
+
+    static {
+        try {
+            System.loadLibrary("GetNamedModuleTest");
+        } catch (UnsatisfiedLinkError ule) {
+            System.err.println("Could not load GetNamedModuleTest library");
+            System.err.println("java.library.path: "
+                + System.getProperty("java.library.path"));
+            throw ule;
+        }
+    }
+
+    native static int check();
+
+    public static void main(String args[]) {
+        int status = check();
+        if (status != 0) {
+            throw new RuntimeException("Non-zero status returned from the agent: " + status);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/GetNamedModule/libGetNamedModuleTest.c	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "jvmti.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_ARG
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG(x, y) y
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG(x,y) x, y
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+#define TranslateError(err) "JVMTI error"
+
+#define PASSED 0
+#define FAILED 2
+
+static const char *EXC_CNAME = "java/lang/Exception";
+static const char* MOD_CNAME = "Ljava/lang/reflect/Module;";
+
+static jvmtiEnv *jvmti = NULL;
+static jint result = PASSED;
+static jboolean printdump = JNI_FALSE;
+
+static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
+
+JNIEXPORT
+jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+    return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
+    return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
+    return JNI_VERSION_1_8;
+}
+
+static
+jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
+    jint res;
+
+    if (options != NULL && strcmp(options, "printdump") == 0) {
+        printdump = JNI_TRUE;
+    }
+
+    res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
+        JVMTI_VERSION_9);
+    if (res != JNI_OK || jvmti == NULL) {
+        printf("    Error: wrong result of a valid call to GetEnv!\n");
+        return JNI_ERR;
+    }
+
+    return JNI_OK;
+}
+
+static
+jint throw_exc(JNIEnv *env, char *msg) {
+    jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
+
+    if (exc_class == NULL) {
+        printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
+        return -1;
+    }
+    return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
+}
+
+static
+jobject get_class_loader(jclass cls) {
+    jvmtiError err = JVMTI_ERROR_NONE;
+    jobject loader = NULL;
+
+    if (printdump == JNI_TRUE) {
+        printf(">>> getting class loader ...\n");
+    }
+    err = (*jvmti)->GetClassLoader(jvmti, cls, &loader);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("    Error in GetClassLoader: %s (%d)\n", TranslateError(err), err);
+    }
+    return loader;
+}
+
+static
+jclass jlrM(JNIEnv *env) {
+    jclass cls = NULL;
+
+    cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME));
+    if (cls == NULL) {
+        printf("    Error in JNI FindClass: %s\n", MOD_CNAME);
+    }
+    return cls;
+}
+
+jmethodID
+get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) {
+    jmethodID method = NULL;
+
+    method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig);
+    if (method == NULL) {
+        printf("    Error in JNI GetMethodID %s with signature %s", name, sig);
+    }
+    return method;
+}
+
+static
+jobject get_module_loader(JNIEnv *env, jobject module) {
+    static jmethodID cl_method = NULL;
+    jobject loader = NULL;
+
+    if (cl_method == NULL) {
+        cl_method = get_method(env, jlrM(env), "getClassLoader", "()Ljava/lang/ClassLoader;");
+    }
+    loader = (jobject)JNI_ENV_PTR(env)->CallObjectMethod(JNI_ENV_ARG(env, module), cl_method);
+    return loader;
+}
+
+static
+const char* get_module_name(JNIEnv *env, jobject module) {
+    static jmethodID method = NULL;
+    jobject loader = NULL;
+    jstring jstr = NULL;
+    const char *name = NULL;
+    const char *nstr = NULL;
+
+    if (method == NULL) {
+        method = get_method(env, jlrM(env), "getName", "()Ljava/lang/String;");
+    }
+    jstr = (jstring)JNI_ENV_PTR(env)->CallObjectMethod(JNI_ENV_ARG(env, module), method);
+    if (jstr != NULL) {
+        name = JNI_ENV_PTR(env)->GetStringUTFChars(JNI_ENV_ARG(env, jstr), NULL);
+    }
+    loader = get_module_loader(env, module);
+    nstr = (name == NULL) ? "<UNNAMED>" : name;
+    printf("    loader: %p, module: %p, name: %s\n", loader, module, nstr);
+    return name;
+}
+
+static
+jvmtiError get_module(JNIEnv *env,
+                      jobject loader,
+                      const char* pkg_name,
+                      jobject* module_ptr,
+                      const char** mod_name_ptr) {
+    jvmtiError err = JVMTI_ERROR_NONE;
+    const char* name = (pkg_name == NULL) ? "<NULL>" : pkg_name;
+
+    printf(">>> getting module by loader %p and package \"%s\"\n", loader, name);
+    *mod_name_ptr = NULL;
+    err = (*jvmti)->GetNamedModule(jvmti, loader, pkg_name, module_ptr);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("    Error in GetNamedModule for package \"%s\": %s (%d)\n",
+               pkg_name, TranslateError(err), err);
+        return err;
+    }
+    printf("    returned module: %p\n", *module_ptr);
+    if (*module_ptr == NULL) { // named module was not found
+        return err;
+    }
+    *mod_name_ptr = get_module_name(env, *module_ptr);
+    return err;
+}
+
+static
+jint get_all_modules(JNIEnv *env) {
+    jvmtiError err;
+    jint cnt = -1;
+    jint idx = 0;
+    jobject* modules;
+
+    printf(">>> Inspecting modules with GetAllModules\n");
+    err = (*jvmti)->GetAllModules(jvmti, &cnt, &modules);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("Error in GetAllModules: %d\n", err);
+        return -1;
+    }
+    for (idx = 0; idx < cnt; ++idx) {
+        get_module_name(env, modules[idx]);
+    }
+    return cnt;
+}
+
+static
+jint check_bad_loader(JNIEnv *env, jobject loader) {
+    jvmtiError err = JVMTI_ERROR_NONE;
+    jobject module = NULL;
+    const char* mod_name = NULL;
+
+    err = get_module(env, loader, "", &module, &mod_name);
+    if (err != JVMTI_ERROR_ILLEGAL_ARGUMENT) {
+        return FAILED;
+    }
+    printf("    got expected JVMTI_ERROR_ILLEGAL_ARGUMENT for bad loader\n");
+    return PASSED;
+}
+
+static
+jint check_system_loader(JNIEnv *env, jobject loader) {
+    jvmtiError err = JVMTI_ERROR_NONE;
+    jobject module = NULL;
+    const char* exp_name = NULL;
+    const char* mod_name = NULL;
+
+    // NULL pointer for package name
+    err = get_module(env, loader, NULL, &module, &mod_name);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        throw_exc(env, "check #SN1: failed to return JVMTI_ERROR_NULL_POINTER for NULL package");
+        return FAILED;
+    }
+
+    // NULL pointer for module_ptr
+    err = (*jvmti)->GetNamedModule(jvmti, loader, "", NULL);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        throw_exc(env, "check #SN2: failed to return JVMTI_ERROR_NULL_POINTER for NULL module_ptr");
+        return FAILED;
+    }
+
+    // Unnamed/default package ""
+    err = get_module(env, loader, "", &module, &mod_name);
+    if (err != JVMTI_ERROR_NONE) {
+        throw_exc(env, "check #S1: failed to return JVMTI_ERROR_NONE for default package");
+        return FAILED;
+    }
+    if (module != NULL || mod_name != NULL) {
+        throw_exc(env, "check #S2: failed to return NULL-module for default package");
+        return FAILED;
+    }
+
+    // Test package: MyPackage
+    err = get_module(env, loader, "MyPackage", &module, &mod_name);
+    if (err != JVMTI_ERROR_NONE) {
+        throw_exc(env, "check #S3: failed to return JVMTI_ERROR_NONE for MyPackage");
+        return FAILED;
+    }
+    if (module != NULL || mod_name != NULL) {
+        throw_exc(env, "check #S4: failed to return NULL-module for MyPackage");
+        return FAILED;
+    }
+
+    // Package: com/sun/jdi
+    exp_name = "jdk.jdi";
+    err = get_module(env, loader, "com/sun/jdi", &module, &mod_name);
+    if (err != JVMTI_ERROR_NONE) {
+        throw_exc(env, "check #S5: failed to return JVMTI_ERROR_NONE for test package");
+        return FAILED;
+    }
+    if (module == NULL || mod_name == NULL) {
+        throw_exc(env, "check #S6: failed to return named module for com/sun/jdi package");
+        return FAILED;
+    }
+    if (strcmp(mod_name, exp_name) != 0) {
+        printf("check #S7: failed to return right module, expected: %s, returned: %s\n",
+               exp_name, mod_name);
+        throw_exc(env, "check #S7: failed to return jdk.jdi module for com/sun/jdi package");
+        return FAILED;
+    }
+
+    // Non-existing package: "bad/package/name"
+    err = get_module(env, loader, "bad/package/name", &module, &mod_name);
+    if (err != JVMTI_ERROR_NONE) {
+        throw_exc(env, "check #S8: failed to return JVMTI_ERROR_NONE for bad package");
+        return FAILED;
+    }
+    if (module != NULL || mod_name != NULL) {
+        throw_exc(env, "check #S9: failed to return NULL-module for bad package");
+        return FAILED;
+    }
+    return PASSED;
+}
+
+static
+jint check_bootstrap_loader(JNIEnv *env, jobject loader) {
+    jvmtiError err = JVMTI_ERROR_NONE;
+    jobject module = NULL;
+    const char* exp_name = NULL;
+    const char* mod_name = NULL;
+
+    // NULL pointer for package name
+    err = get_module(env, loader, NULL, &module, &mod_name);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        throw_exc(env, "check #BN1: failed to return JVMTI_ERROR_NULL_POINTER for NULL package");
+        return FAILED;
+    }
+
+    // NULL pointer for module_ptr
+    err = (*jvmti)->GetNamedModule(jvmti, loader, "", NULL);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        throw_exc(env, "check #BN2: failed to return JVMTI_ERROR_NULL_POINTER for NULL module_ptr");
+        return FAILED;
+    }
+
+    // Unnamed/default package ""
+    err = get_module(env, loader, "", &module, &mod_name);
+    if (err != JVMTI_ERROR_NONE) {
+        throw_exc(env, "check #B1: failed to return JVMTI_ERROR_NONE for default package");
+        return FAILED;
+    }
+    if (module != NULL || mod_name != NULL) {
+        throw_exc(env, "check #B2: failed to return NULL-module for default package");
+        return FAILED;
+    }
+
+    // Normal package from java.base module: "java/lang"
+    exp_name = "java.base";
+    err = get_module(env, loader, "java/lang", &module, &mod_name);
+    if (err != JVMTI_ERROR_NONE) {
+        throw_exc(env, "check #B3: failed to return JVMTI_ERROR_NONE for java/lang package");
+        return FAILED;
+    }
+    if (module == NULL || mod_name == NULL) {
+        throw_exc(env, "check #B4: failed to return named module for java/lang package");
+        return FAILED;
+    }
+    if (strcmp(exp_name, mod_name) != 0) {
+        printf("check #B5: failed to return right module, expected: %s, returned: %s\n",
+               exp_name, mod_name);
+        throw_exc(env, "check #B5: failed to return expected module for java/lang package");
+        return FAILED;
+    }
+
+    // Non-existing package: "bad/package/name"
+    err = get_module(env, loader, "bad/package/name", &module, &mod_name);
+    if (err != JVMTI_ERROR_NONE) {
+        throw_exc(env, "check #B6: failed to return JVMTI_ERROR_NONE for bad package");
+        return FAILED;
+    }
+    if (module != NULL || mod_name != NULL) {
+        throw_exc(env, "check #B7: failed to return NULL-module for bad package");
+        return FAILED;
+    }
+    return PASSED;
+}
+
+JNIEXPORT jint JNICALL
+Java_MyPackage_GetNamedModuleTest_check(JNIEnv *env, jclass cls) {
+    jobject loader = NULL;
+
+    if (jvmti == NULL) {
+        throw_exc(env, "JVMTI client was not properly loaded!\n");
+        return FAILED;
+    }
+
+    get_all_modules(env);
+
+    printf("\n*** Check for bad ClassLoader ***\n\n");
+    result = check_bad_loader(env, (jobject)cls);
+    if (result != PASSED) {
+        throw_exc(env, "check #L1: failed to return JVMTI_ERROR_ILLEGAL_ARGUMENT for bad loader");
+        return result;
+    }
+
+    loader = get_class_loader(cls);
+    if (loader == NULL) {
+        throw_exc(env, "check #L2: failed to return non-NULL loader for valid test class");
+        return FAILED;
+    }
+
+    printf("\n*** Checks for System ClassLoader ***\n\n");
+    result = check_system_loader(env, loader);
+    if (result != PASSED) {
+        return result;
+    }
+
+    printf("\n*** Checks for Bootstrap ClassLoader ***\n\n");
+    result = check_bootstrap_loader(env, NULL);
+
+    return result;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- a/hotspot/test/serviceability/sa/TestClassLoaderStats.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/serviceability/sa/TestClassLoaderStats.java	Wed Jul 05 22:00:06 2017 +0200
@@ -32,6 +32,9 @@
 
 /*
  * @test
+ * @summary Started failing on 2016.06.24 due to 8160376 on MacOS X so
+ * quarantine it on that platform:
+ * @requires os.family != "mac"
  * @modules java.base/jdk.internal.misc
  * @library /test/lib/share/classes
  * @library /testlibrary
--- a/hotspot/test/serviceability/sa/TestStackTrace.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/serviceability/sa/TestStackTrace.java	Wed Jul 05 22:00:06 2017 +0200
@@ -32,6 +32,9 @@
 
 /*
  * @test
+ * @summary Started failing on 2016.06.24 due to 8160376 on MacOS X so
+ * quarantine it on that platform:
+ * @requires os.family != "mac"
  * @modules java.base/jdk.internal.misc
  * @library /test/lib/share/classes
  * @library /testlibrary
--- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -43,6 +43,9 @@
  * @bug 6313383
  * @key regression
  * @summary Regression test for hprof export issue due to large heaps (>2G)
+ * Started failing on 2016.06.24 due to 8160376 on MacOS X so quarantine
+ * it on that platform:
+ * @requires os.family != "mac"
  * @library /testlibrary
  * @modules java.base/jdk.internal.misc
  *          java.compiler
--- a/jaxp/.hgtags	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/.hgtags	Wed Jul 05 22:00:06 2017 +0200
@@ -370,3 +370,4 @@
 493eb91ec32a6dea7604cfbd86c10045ad9af15b jdk-9+125
 15722f71281f034bc696d8b96136da2ef34da44f jdk-9+126
 bdc3c0b737efbf899709eb3121ce760dcfb51151 jdk-9+127
+8a7681a9d70640ac7fbf05c28f53c1d51d8d00a1 jdk-9+128
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/XalanConstants.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/XalanConstants.java	Wed Jul 05 22:00:06 2017 +0200
@@ -80,6 +80,14 @@
      */
     public static final String JDK_GENERAL_ENTITY_SIZE_LIMIT =
             ORACLE_JAXP_PROPERTY_PREFIX + "maxGeneralEntitySizeLimit";
+
+    /**
+     * JDK node count limit in entities that limits the total number of nodes
+     * in all of entity references.
+     */
+    public static final String JDK_ENTITY_REPLACEMENT_LIMIT =
+            ORACLE_JAXP_PROPERTY_PREFIX + "entityReplacementLimit";
+
     /**
      * JDK maximum parameter entity size limit
      */
@@ -136,6 +144,13 @@
      * JDK maximum general entity size limit
      */
     public static final String SP_GENERAL_ENTITY_SIZE_LIMIT = "jdk.xml.maxGeneralEntitySizeLimit";
+
+    /**
+     * JDK node count limit in entities that limits the total number of nodes
+     * in all of entity references.
+     */
+    public static final String SP_ENTITY_REPLACEMENT_LIMIT = "jdk.xml.entityReplacementLimit";
+
     /**
      * JDK maximum parameter entity size limit
      */
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/XMLSecurityManager.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/XMLSecurityManager.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -82,7 +82,9 @@
         MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit", XalanConstants.JDK_MAX_ELEMENT_DEPTH,
                 XalanConstants.SP_MAX_ELEMENT_DEPTH, 0, 0),
         MAX_NAME_LIMIT("MaxXMLNameLimit", XalanConstants.JDK_XML_NAME_LIMIT,
-                XalanConstants.SP_XML_NAME_LIMIT, 1000, 1000);
+                XalanConstants.SP_XML_NAME_LIMIT, 1000, 1000),
+        ENTITY_REPLACEMENT_LIMIT("EntityReplacementLimit", XalanConstants.JDK_ENTITY_REPLACEMENT_LIMIT,
+                XalanConstants.SP_ENTITY_REPLACEMENT_LIMIT, 0, 3000000);
 
         final String key;
         final String apiProperty;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Constants.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Constants.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,15 +1,15 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
- * Copyright 2001-2004 The Apache Software Foundation.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -98,6 +98,10 @@
     public static final int ACC_STATIC
         = com.sun.org.apache.bcel.internal.Constants.ACC_STATIC;
 
+    public static final String MODULE_SIG
+        = "Ljava/lang/reflect/Module;";
+    public static final String CLASS_SIG
+        = "Ljava/lang/Class;";
     public static final String STRING_SIG
         = "Ljava/lang/String;";
     public static final String STRING_BUFFER_SIG
@@ -246,8 +250,12 @@
         = "com.sun.org.apache.xalan.internal.xsltc.DOM";
     public static final String DOM_IMPL
         = "com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl";
-        public static final String SAX_IMPL
+    public static final String SAX_IMPL
         = "com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl";
+    public static final String CLASS_CLASS
+        = "java.lang.Class";
+    public static final String MODULE_CLASS
+        = "java.lang.reflect.Module";
     public static final String STRING_CLASS
         = "java.lang.String";
     public static final String OBJECT_CLASS
@@ -293,7 +301,7 @@
         = "()D";
 
     public static final String DOM_PNAME
-  = "dom";
+        = "dom";
     public static final String NODE_PNAME
         = "node";
     public static final String TRANSLET_OUTPUT_PNAME
@@ -335,6 +343,19 @@
         = "setStartNode";
     public static final String RESET
         = "reset";
+    public static final String GET_MODULE
+        = "getModule";
+    public static final String FOR_NAME
+        = "forName";
+    public static final String ADD_READS
+        = "addReads";
+
+    public static final String GET_MODULE_SIG
+        = "()" + MODULE_SIG;
+    public static final String FOR_NAME_SIG
+        = "(" + STRING_SIG + ")" + CLASS_SIG;
+    public static final String ADD_READS_SIG
+        = "(" + MODULE_SIG + ")" + MODULE_SIG;
 
     public static final String ATTR_SET_SIG
         = "(" + DOM_INTF_SIG  + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + "I)V";
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -17,9 +17,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: FunctionCall.java,v 1.2.4.1 2005/09/12 10:31:32 pvedula Exp $
- */
 
 package com.sun.org.apache.xalan.internal.xsltc.compiler;
 
@@ -32,6 +29,7 @@
 import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
 import com.sun.org.apache.bcel.internal.generic.InstructionList;
 import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
+import com.sun.org.apache.bcel.internal.generic.LDC;
 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
 import com.sun.org.apache.bcel.internal.generic.NEW;
 import com.sun.org.apache.bcel.internal.generic.PUSH;
@@ -792,6 +790,11 @@
 
             final String clazz =
                 _chosenConstructor.getDeclaringClass().getName();
+
+            // Generate call to Module.addReads:
+            //   <TransletClass>.class.getModule().addReads(
+            generateAddReads(classGen, methodGen, clazz);
+
             Class[] paramTypes = _chosenConstructor.getParameterTypes();
             LocalVariableGen[] paramTemp = new LocalVariableGen[n];
 
@@ -855,6 +858,12 @@
             final String clazz = _chosenMethod.getDeclaringClass().getName();
             Class[] paramTypes = _chosenMethod.getParameterTypes();
 
+
+            // Generate call to Module.addReads:
+            //   <TransletClass>.class.getModule().addReads(
+            //        Class.forName(<clazz>).getModule());
+            generateAddReads(classGen, methodGen, clazz);
+
             // Push "this" if it is an instance method
             if (_thisArgument != null) {
                 _thisArgument.translate(classGen, methodGen);
@@ -896,6 +905,41 @@
         }
     }
 
+    private void generateAddReads(ClassGenerator classGen, MethodGenerator methodGen,
+                          String clazz) {
+        final ConstantPoolGen cpg = classGen.getConstantPool();
+        final InstructionList il = methodGen.getInstructionList();
+
+        // Generate call to Module.addReads:
+        //   <TransletClass>.class.getModule().addReads(
+        //        Class.forName(<clazz>).getModule());
+        // Class.forName may throw ClassNotFoundException.
+        // This is OK as it will caught higher up the stack in
+        // TransformerImpl.transform() and wrapped into a
+        // TransformerException.
+        methodGen.markChunkStart();
+
+        int index = cpg.addMethodref(CLASS_CLASS,
+                                     GET_MODULE,
+                                     GET_MODULE_SIG);
+        int index2 = cpg.addMethodref(CLASS_CLASS,
+                                      FOR_NAME,
+                                      FOR_NAME_SIG);
+        il.append(new LDC(cpg.addString(classGen.getClassName())));
+        il.append(new INVOKESTATIC(index2));
+        il.append(new INVOKEVIRTUAL(index));
+        il.append(new LDC(cpg.addString(clazz)));
+        il.append(new INVOKESTATIC(index2));
+        il.append(new INVOKEVIRTUAL(index));
+        index = cpg.addMethodref(MODULE_CLASS,
+                                 ADD_READS,
+                                 ADD_READS_SIG);
+        il.append(new INVOKEVIRTUAL(index));
+        il.append(InstructionConstants.POP);
+
+        methodGen.markChunkEnd();
+    }
+
     @Override
     public String toString() {
         return "funcall(" + _fname + ", " + _arguments + ')';
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -58,7 +58,6 @@
 import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.URIResolver;
 
-import jdk.internal.module.Modules;
 
 /**
  * @author Morten Jorgensen
@@ -486,10 +485,6 @@
                 thisModule.addExports(p, m);
             });
 
-            // For now, the module reads all unnnamed modules. This will be changed once
-            // the XSLT compiler is updated to generate code to invoke addReads.
-            Modules.addReadsAllUnnamed(m);
-
             // java.xml needs to instanitate the translet class
             thisModule.addReads(m);
 
@@ -513,7 +508,7 @@
         }
         catch (ClassFormatError e) {
             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
-            throw new TransformerConfigurationException(err.toString());
+            throw new TransformerConfigurationException(err.toString(), e);
         }
         catch (LinkageError e) {
             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/Constants.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/Constants.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -239,6 +239,14 @@
      */
     public static final String JDK_GENERAL_ENTITY_SIZE_LIMIT =
             ORACLE_JAXP_PROPERTY_PREFIX + "maxGeneralEntitySizeLimit";
+
+    /**
+     * JDK node count limit in entities that limits the total number of nodes
+     * in all of entity references.
+     */
+    public static final String JDK_ENTITY_REPLACEMENT_LIMIT =
+            ORACLE_JAXP_PROPERTY_PREFIX + "entityReplacementLimit";
+
     /**
      * JDK maximum parameter entity size limit
      */
@@ -292,6 +300,13 @@
      * JDK maximum general entity size limit
      */
     public static final String SP_GENERAL_ENTITY_SIZE_LIMIT = "jdk.xml.maxGeneralEntitySizeLimit";
+
+    /**
+     * JDK node count limit in entities that limits the total number of nodes
+     * in all of entity references.
+     */
+    public static final String SP_ENTITY_REPLACEMENT_LIMIT = "jdk.xml.entityReplacementLimit";
+
     /**
      * JDK maximum parameter entity size limit
      */
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DTDScannerImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DTDScannerImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,62 +1,21 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999-2004 The Apache Software Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- *    if any, must include the following acknowledgment:
- *       "This product includes software developed by the
- *        Apache Software Foundation (http://www.apache.org/)."
- *    Alternately, this acknowledgment may appear in the software itself,
- *    if and wherever such third-party acknowledgments normally appear.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * 4. The names "Xerces" and "Apache Software Foundation" must
- *    not be used to endorse or promote products derived from this
- *    software without prior written permission. For written
- *    permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- *    nor may "Apache" appear in their name, without prior written
- *    permission of the Apache Software Foundation.
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 1999, International
- * Business Machines, Inc., http://www.apache.org.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package com.sun.org.apache.xerces.internal.impl;
@@ -146,7 +105,7 @@
     protected boolean scanPubidLiteral(XMLString literal)
         throws IOException, XNIException
     {
-        int quote = fEntityScanner.scanChar();
+        int quote = fEntityScanner.scanChar(null);
         if (quote != '\'' && quote != '"') {
             reportFatalError("QuoteRequiredInPublicID", null);
             return false;
@@ -157,7 +116,7 @@
         boolean skipSpace = true;
         boolean dataok = true;
         while (true) {
-            int c = fEntityScanner.scanChar();
+            int c = fEntityScanner.scanChar(null);
             // REVISIT:  it could really only be \n or 0x20; all else is normalized, no?  - neilg
             if (c == ' ' || c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) {
                 if (!skipSpace) {
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DocumentScannerImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DocumentScannerImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,62 +1,21 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999-2004 The Apache Software Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- *    if any, must include the following acknowledgment:
- *       "This product includes software developed by the
- *        Apache Software Foundation (http://www.apache.org/)."
- *    Alternately, this acknowledgment may appear in the software itself,
- *    if and wherever such third-party acknowledgments normally appear.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * 4. The names "Xerces" and "Apache Software Foundation" must
- *    not be used to endorse or promote products derived from this
- *    software without prior written permission. For written
- *    permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- *    nor may "Apache" appear in their name, without prior written
- *    permission of the Apache Software Foundation.
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 1999, International
- * Business Machines, Inc., http://www.apache.org.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package com.sun.org.apache.xerces.internal.impl;
@@ -134,7 +93,7 @@
             // happens when there is the character reference &#13;
             // but scanContent doesn't do entity expansions...
             // is this *really* necessary???  - NG
-            fEntityScanner.scanChar();
+            fEntityScanner.scanChar(null);
             content.append((char)c);
             c = -1;
         }
@@ -143,7 +102,7 @@
         } */
 
         if (c == ']') {
-            content.append((char)fEntityScanner.scanChar());
+            content.append((char)fEntityScanner.scanChar(null));
             // remember where we are in case we get an endEntity before we
             // could flush the buffer out - this happens when we're parsing an
             // entity which ends with a ]
@@ -152,12 +111,12 @@
             // We work on a single character basis to handle cases such as:
             // ']]]>' which we might otherwise miss.
             //
-            if (fEntityScanner.skipChar(']')) {
+            if (fEntityScanner.skipChar(']', null)) {
                 content.append(']');
-                while (fEntityScanner.skipChar(']')) {
+                while (fEntityScanner.skipChar(']', null)) {
                     content.append(']');
                 }
-                if (fEntityScanner.skipChar('>')) {
+                if (fEntityScanner.skipChar('>', null)) {
                     reportFatalError("CDEndInContent", null);
                 }
             }
@@ -184,6 +143,7 @@
      * @param checkEntities true if undeclared entities should be reported as VC violation,
      *                      false if undeclared entities should be reported as WFC violation.
      * @param eleName The name of element to which this attribute belongs.
+     * @param isNSURI The flag indicating whether the content is a namespace URI
      *
      * @return true if the non-normalized and normalized value are the same
      *
@@ -193,7 +153,7 @@
     protected boolean scanAttributeValue(XMLString value,
                                       XMLString nonNormalizedValue,
                                       String atName,
-                                      boolean checkEntities,String eleName)
+                                      boolean checkEntities,String eleName, boolean isNSURI)
         throws IOException, XNIException
     {
         // quote
@@ -202,10 +162,10 @@
             reportFatalError("OpenQuoteExpected", new Object[]{eleName,atName});
         }
 
-        fEntityScanner.scanChar();
+        fEntityScanner.scanChar(NameType.ATTRIBUTE);
         int entityDepth = fEntityDepth;
 
-        int c = fEntityScanner.scanLiteral(quote, value);
+        int c = fEntityScanner.scanLiteral(quote, value, isNSURI);
         if (DEBUG_ATTR_NORMALIZATION) {
             System.out.println("** scanLiteral -> \""
                                + value.toString() + "\"");
@@ -215,7 +175,7 @@
         if (c == quote && (fromIndex = isUnchangedByNormalization(value)) == -1) {
             /** Both the non-normalized and normalized attribute values are equal. **/
             nonNormalizedValue.setValues(value);
-            int cquote = fEntityScanner.scanChar();
+            int cquote = fEntityScanner.scanChar(NameType.ATTRIBUTE);
             if (cquote != quote) {
                 reportFatalError("CloseQuoteExpected", new Object[]{eleName,atName});
             }
@@ -238,11 +198,11 @@
                                        + fStringBuffer.toString() + "\"");
                 }
                 if (c == '&') {
-                    fEntityScanner.skipChar('&');
+                    fEntityScanner.skipChar('&', NameType.REFERENCE);
                     if (entityDepth == fEntityDepth) {
                         fStringBuffer2.append('&');
                     }
-                    if (fEntityScanner.skipChar('#')) {
+                    if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
                         if (entityDepth == fEntityDepth) {
                             fStringBuffer2.append('#');
                         }
@@ -256,59 +216,22 @@
                         }
                     }
                     else {
-                        String entityName = fEntityScanner.scanName();
+                        String entityName = fEntityScanner.scanName(NameType.REFERENCE);
                         if (entityName == null) {
                             reportFatalError("NameRequiredInReference", null);
                         }
                         else if (entityDepth == fEntityDepth) {
                             fStringBuffer2.append(entityName);
                         }
-                        if (!fEntityScanner.skipChar(';')) {
+                        if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
                             reportFatalError("SemicolonRequiredInReference",
                                              new Object []{entityName});
                         }
                         else if (entityDepth == fEntityDepth) {
                             fStringBuffer2.append(';');
                         }
-                        if (entityName == fAmpSymbol) {
-                            fStringBuffer.append('&');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** value5: \""
-                                                   + fStringBuffer.toString()
-                                                   + "\"");
-                            }
-                        }
-                        else if (entityName == fAposSymbol) {
-                            fStringBuffer.append('\'');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** value7: \""
-                                                   + fStringBuffer.toString()
-                                                   + "\"");
-                            }
-                        }
-                        else if (entityName == fLtSymbol) {
-                            fStringBuffer.append('<');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** value9: \""
-                                                   + fStringBuffer.toString()
-                                                   + "\"");
-                            }
-                        }
-                        else if (entityName == fGtSymbol) {
-                            fStringBuffer.append('>');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** valueB: \""
-                                                   + fStringBuffer.toString()
-                                                   + "\"");
-                            }
-                        }
-                        else if (entityName == fQuotSymbol) {
-                            fStringBuffer.append('"');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** valueD: \""
-                                                   + fStringBuffer.toString()
-                                                   + "\"");
-                            }
+                        if (resolveCharacter(entityName, fStringBuffer)) {
+                            checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
                         }
                         else {
                             if (fEntityManager.isExternalEntity(entityName)) {
@@ -339,13 +262,13 @@
                 else if (c == '<') {
                     reportFatalError("LessthanInAttValue",
                                      new Object[] { eleName, atName });
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     if (entityDepth == fEntityDepth) {
                         fStringBuffer2.append((char)c);
                     }
                 }
                 else if (c == '%' || c == ']') {
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     fStringBuffer.append((char)c);
                     if (entityDepth == fEntityDepth) {
                         fStringBuffer2.append((char)c);
@@ -359,7 +282,7 @@
                 // XML11EntityScanner.  Not sure why
                 // this check was originally necessary.  - NG
                 else if (c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) {
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     fStringBuffer.append(' ');
                     if (entityDepth == fEntityDepth) {
                         fStringBuffer2.append('\n');
@@ -382,12 +305,12 @@
                 else if (c != -1 && isInvalidLiteral(c)) {
                     reportFatalError("InvalidCharInAttValue",
                                      new Object[] {eleName, atName, Integer.toString(c, 16)});
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     if (entityDepth == fEntityDepth) {
                         fStringBuffer2.append((char)c);
                     }
                 }
-                c = fEntityScanner.scanLiteral(quote, value);
+                c = fEntityScanner.scanLiteral(quote, value, isNSURI);
                 if (entityDepth == fEntityDepth) {
                     fStringBuffer2.append(value);
                 }
@@ -404,7 +327,7 @@
         nonNormalizedValue.setValues(fStringBuffer2);
 
         // quote
-        int cquote = fEntityScanner.scanChar();
+        int cquote = fEntityScanner.scanChar(null);
         if (cquote != quote) {
             reportFatalError("CloseQuoteExpected", new Object[]{eleName,atName});
         }
@@ -439,7 +362,7 @@
     protected boolean scanPubidLiteral(XMLString literal)
         throws IOException, XNIException
     {
-        int quote = fEntityScanner.scanChar();
+        int quote = fEntityScanner.scanChar(null);
         if (quote != '\'' && quote != '"') {
             reportFatalError("QuoteRequiredInPublicID", null);
             return false;
@@ -450,7 +373,7 @@
         boolean skipSpace = true;
         boolean dataok = true;
         while (true) {
-            int c = fEntityScanner.scanChar();
+            int c = fEntityScanner.scanChar(null);
             // REVISIT:  none of these except \n and 0x20 should make it past the entity scanner
             if (c == ' ' || c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) {
                 if (!skipSpace) {
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java	Wed Jul 05 22:00:06 2017 +0200
@@ -21,6 +21,7 @@
 
 package com.sun.org.apache.xerces.internal.impl;
 
+import com.sun.org.apache.xerces.internal.impl.XMLScanner.NameType;
 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
 import com.sun.org.apache.xerces.internal.util.XML11Char;
 import com.sun.org.apache.xerces.internal.util.XMLChar;
@@ -92,7 +93,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public int scanChar() throws IOException {
+    protected int scanChar(NameType nt) throws IOException {
 
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -100,6 +101,7 @@
         }
 
         // scan character
+        int offset = fCurrentEntity.position;
         int c = fCurrentEntity.ch[fCurrentEntity.position++];
         boolean external = false;
         if (c == '\n' ||
@@ -110,6 +112,7 @@
                 invokeListeners(1);
                 fCurrentEntity.ch[0] = (char)c;
                 load(1, false, false);
+                offset = 0;
             }
             if (c == '\r' && external) {
                 int cc = fCurrentEntity.ch[fCurrentEntity.position++];
@@ -122,6 +125,9 @@
 
         // return character that was scanned
         fCurrentEntity.columnNumber++;
+        if (!detectingVersion) {
+            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
+        }
         return c;
 
     } // scanChar():int
@@ -141,7 +147,7 @@
      * @see com.sun.org.apache.xerces.internal.util.SymbolTable
      * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
      */
-    public String scanNmtoken() throws IOException {
+    protected String scanNmtoken() throws IOException {
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
             load(0, true, true);
@@ -248,6 +254,8 @@
      * <strong>Note:</strong> The string returned must be a symbol. The
      * SymbolTable can be used for this purpose.
      *
+     * @param nt The type of the name (element or attribute)
+     *
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      *
@@ -255,7 +263,7 @@
      * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
      * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NameStart
      */
-    public String scanName() throws IOException {
+    protected String scanName(NameType nt) throws IOException {
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
             load(0, true, true);
@@ -310,23 +318,11 @@
             return null;
         }
 
+        int length = 0;
         do {
             ch = fCurrentEntity.ch[fCurrentEntity.position];
             if (XML11Char.isXML11Name(ch)) {
-                if (++fCurrentEntity.position == fCurrentEntity.count) {
-                    int length = fCurrentEntity.position - offset;
-                    invokeListeners(length);
-                    if (length == fCurrentEntity.ch.length) {
-                        // bad luck we have to resize our buffer
-                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         tmp, 0, length);
-                        fCurrentEntity.ch = tmp;
-                    }
-                    else {
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         fCurrentEntity.ch, 0, length);
-                    }
+                if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
                     offset = 0;
                     if (load(length, false, false)) {
                         break;
@@ -334,20 +330,7 @@
                 }
             }
             else if (XML11Char.isXML11NameHighSurrogate(ch)) {
-                if (++fCurrentEntity.position == fCurrentEntity.count) {
-                    int length = fCurrentEntity.position - offset;
-                    invokeListeners(length);
-                    if (length == fCurrentEntity.ch.length) {
-                        // bad luck we have to resize our buffer
-                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         tmp, 0, length);
-                        fCurrentEntity.ch = tmp;
-                    }
-                    else {
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         fCurrentEntity.ch, 0, length);
-                    }
+                if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
                     offset = 0;
                     if (load(length, false, false)) {
                         --fCurrentEntity.position;
@@ -361,20 +344,7 @@
                     --fCurrentEntity.position;
                     break;
                 }
-                if (++fCurrentEntity.position == fCurrentEntity.count) {
-                    int length = fCurrentEntity.position - offset;
-                    invokeListeners(length);
-                    if (length == fCurrentEntity.ch.length) {
-                        // bad luck we have to resize our buffer
-                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         tmp, 0, length);
-                        fCurrentEntity.ch = tmp;
-                    }
-                    else {
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         fCurrentEntity.ch, 0, length);
-                    }
+                if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
                     offset = 0;
                     if (load(length, false, false)) {
                         break;
@@ -387,12 +357,14 @@
         }
         while (true);
 
-        int length = fCurrentEntity.position - offset;
+        length = fCurrentEntity.position - offset;
         fCurrentEntity.columnNumber += length;
 
         // return name
         String symbol = null;
         if (length > 0) {
+            checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
+            checkEntityLimit(nt, fCurrentEntity, offset, length);
             symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
         }
         return symbol;
@@ -415,7 +387,7 @@
      * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NCName
      * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NCNameStart
      */
-    public String scanNCName() throws IOException {
+    protected String scanNCName() throws IOException {
 
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -571,6 +543,7 @@
      * this purpose.
      *
      * @param qname The qualified name structure to fill.
+     * @param nt The type of the name (element or attribute)
      *
      * @return Returns true if a qualified name appeared immediately on
      *         the input and was scanned, false otherwise.
@@ -582,7 +555,7 @@
      * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
      * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NameStart
      */
-    public boolean scanQName(QName qname) throws IOException {
+    protected boolean scanQName(QName qname, XMLScanner.NameType nt) throws IOException {
 
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -602,6 +575,7 @@
                     fCurrentEntity.columnNumber++;
                     String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1);
                     qname.setValues(null, name, name, null);
+                    checkEntityLimit(nt, fCurrentEntity, 0, 1);
                     return true;
                 }
             }
@@ -632,6 +606,7 @@
                     fCurrentEntity.columnNumber += 2;
                     String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2);
                     qname.setValues(null, name, name, null);
+                    checkEntityLimit(nt, fCurrentEntity, 0, 2);
                     return true;
                 }
             }
@@ -641,6 +616,7 @@
         }
 
         int index = -1;
+        int length = 0;
         boolean sawIncompleteSurrogatePair = false;
         do {
             ch = fCurrentEntity.ch[fCurrentEntity.position];
@@ -653,22 +629,7 @@
                     //check prefix before further read
                     checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, index - offset);
                 }
-                if (++fCurrentEntity.position == fCurrentEntity.count) {
-                    int length = fCurrentEntity.position - offset;
-                    //check localpart before loading more data
-                    checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length - index - 1);
-                    invokeListeners(length);
-                    if (length == fCurrentEntity.ch.length) {
-                        // bad luck we have to resize our buffer
-                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         tmp, 0, length);
-                        fCurrentEntity.ch = tmp;
-                    }
-                    else {
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         fCurrentEntity.ch, 0, length);
-                    }
+                if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
                     if (index != -1) {
                         index = index - offset;
                     }
@@ -679,20 +640,7 @@
                 }
             }
             else if (XML11Char.isXML11NameHighSurrogate(ch)) {
-                if (++fCurrentEntity.position == fCurrentEntity.count) {
-                    int length = fCurrentEntity.position - offset;
-                    invokeListeners(length);
-                    if (length == fCurrentEntity.ch.length) {
-                        // bad luck we have to resize our buffer
-                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         tmp, 0, length);
-                        fCurrentEntity.ch = tmp;
-                    }
-                    else {
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         fCurrentEntity.ch, 0, length);
-                    }
+                if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
                     if (index != -1) {
                         index = index - offset;
                     }
@@ -711,20 +659,7 @@
                     --fCurrentEntity.position;
                     break;
                 }
-                if (++fCurrentEntity.position == fCurrentEntity.count) {
-                    int length = fCurrentEntity.position - offset;
-                    invokeListeners(length);
-                    if (length == fCurrentEntity.ch.length) {
-                        // bad luck we have to resize our buffer
-                        char[] tmp = new char[fCurrentEntity.ch.length << 1];
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         tmp, 0, length);
-                        fCurrentEntity.ch = tmp;
-                    }
-                    else {
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                         fCurrentEntity.ch, 0, length);
-                    }
+                if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
                     if (index != -1) {
                         index = index - offset;
                     }
@@ -740,7 +675,7 @@
         }
         while (true);
 
-        int length = fCurrentEntity.position - offset;
+        length = fCurrentEntity.position - offset;
         fCurrentEntity.columnNumber += length;
 
         if (length > 0) {
@@ -776,6 +711,7 @@
                 checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
             }
             qname.setValues(prefix, localpart, rawname, null);
+            checkEntityLimit(nt, fCurrentEntity, offset, length);
             return true;
         }
         return false;
@@ -808,7 +744,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public int scanContent(XMLString content) throws IOException {
+    protected int scanContent(XMLString content) throws IOException {
 
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -826,6 +762,7 @@
         int offset = fCurrentEntity.position;
         int c = fCurrentEntity.ch[offset];
         int newlines = 0;
+        boolean counted = false;
         boolean external = fCurrentEntity.isExternal();
         if (c == '\n' || ((c == '\r' || c == 0x85 || c == 0x2028) && external)) {
             do {
@@ -835,11 +772,13 @@
                     fCurrentEntity.lineNumber++;
                     fCurrentEntity.columnNumber = 1;
                     if (fCurrentEntity.position == fCurrentEntity.count) {
+                        checkEntityLimit(null, fCurrentEntity, offset, newlines);
                         offset = 0;
                         fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
                         fCurrentEntity.position = newlines;
                         fCurrentEntity.startPosition = newlines;
                         if (load(newlines, false, true)) {
+                            counted = true;
                             break;
                         }
                     }
@@ -858,11 +797,13 @@
                     fCurrentEntity.lineNumber++;
                     fCurrentEntity.columnNumber = 1;
                     if (fCurrentEntity.position == fCurrentEntity.count) {
+                        checkEntityLimit(null, fCurrentEntity, offset, newlines);
                         offset = 0;
                         fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
                         fCurrentEntity.position = newlines;
                         fCurrentEntity.startPosition = newlines;
                         if (load(newlines, false, true)) {
+                            counted = true;
                             break;
                         }
                     }
@@ -877,6 +818,7 @@
             }
             int length = fCurrentEntity.position - offset;
             if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+                checkEntityLimit(null, fCurrentEntity, offset, length);
                 content.setValues(fCurrentEntity.ch, offset, length);
                 return -1;
             }
@@ -904,8 +846,8 @@
         }
         int length = fCurrentEntity.position - offset;
         fCurrentEntity.columnNumber += length - newlines;
-        if (fCurrentEntity.isGE) {
-            checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length);
+        if (!counted) {
+            checkEntityLimit(null, fCurrentEntity, offset, length);
         }
         content.setValues(fCurrentEntity.ch, offset, length);
 
@@ -945,6 +887,7 @@
      * @param quote   The quote character that signifies the end of the
      *                attribute value data.
      * @param content The content structure to fill.
+     * @param isNSURI a flag indicating whether the content is a Namespace URI
      *
      * @return Returns the next character on the input, if known. This
      *         value may be -1 but this does <em>note</em> designate
@@ -953,7 +896,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public int scanLiteral(int quote, XMLString content)
+    protected int scanLiteral(int quote, XMLString content, boolean isNSURI)
         throws IOException {
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -1051,8 +994,10 @@
         }
         int length = fCurrentEntity.position - offset;
         fCurrentEntity.columnNumber += length - newlines;
-        if (fCurrentEntity.isGE) {
-            checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length);
+
+        checkEntityLimit(null, fCurrentEntity, offset, length);
+        if (isNSURI) {
+            checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
         }
         content.setValues(fCurrentEntity.ch, offset, length);
 
@@ -1103,7 +1048,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public boolean scanData(String delimiter, XMLStringBuffer buffer)
+    protected boolean scanData(String delimiter, XMLStringBuffer buffer)
         throws IOException {
 
         boolean done = false;
@@ -1135,6 +1080,7 @@
             if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) {
                 // something must be wrong with the input:  e.g., file ends  an unterminated comment
                 int length = fCurrentEntity.count - fCurrentEntity.position;
+                checkEntityLimit(NameType.COMMENT, fCurrentEntity, fCurrentEntity.position, length);
                 buffer.append (fCurrentEntity.ch, fCurrentEntity.position, length);
                 fCurrentEntity.columnNumber += fCurrentEntity.count;
                 fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
@@ -1199,6 +1145,7 @@
                 }
                 int length = fCurrentEntity.position - offset;
                 if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+                    checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
                     buffer.append(fCurrentEntity.ch, offset, length);
                     return true;
                 }
@@ -1237,6 +1184,7 @@
                         fCurrentEntity.position--;
                         int length = fCurrentEntity.position - offset;
                         fCurrentEntity.columnNumber += length - newlines;
+                        checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
                         buffer.append(fCurrentEntity.ch, offset, length);
                         return true;
                     }
@@ -1274,6 +1222,7 @@
                         fCurrentEntity.position--;
                         int length = fCurrentEntity.position - offset;
                         fCurrentEntity.columnNumber += length - newlines;
+                        checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
                         buffer.append(fCurrentEntity.ch, offset, length);
                         return true;
                     }
@@ -1281,6 +1230,7 @@
             }
             int length = fCurrentEntity.position - offset;
             fCurrentEntity.columnNumber += length - newlines;
+            checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
             if (done) {
                 length -= delimLen;
             }
@@ -1305,7 +1255,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public boolean skipChar(int c) throws IOException {
+    protected boolean skipChar(int c, NameType nt) throws IOException {
 
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -1313,6 +1263,7 @@
         }
 
         // skip character
+        int offset = fCurrentEntity.position;
         int cc = fCurrentEntity.ch[fCurrentEntity.position];
         if (cc == c) {
             fCurrentEntity.position++;
@@ -1323,12 +1274,14 @@
             else {
                 fCurrentEntity.columnNumber++;
             }
+            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
             return true;
         }
         else if (c == '\n' && ((cc == 0x2028 || cc == 0x85) && fCurrentEntity.isExternal())) {
             fCurrentEntity.position++;
             fCurrentEntity.lineNumber++;
             fCurrentEntity.columnNumber = 1;
+            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
             return true;
         }
         else if (c == '\n' && (cc == '\r' ) && fCurrentEntity.isExternal()) {
@@ -1344,6 +1297,7 @@
             }
             fCurrentEntity.lineNumber++;
             fCurrentEntity.columnNumber = 1;
+            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
             return true;
         }
 
@@ -1366,7 +1320,7 @@
      * @see com.sun.org.apache.xerces.internal.util.XMLChar#isSpace
      * @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Space
      */
-    public boolean skipSpaces() throws IOException {
+    protected boolean skipSpaces() throws IOException {
 
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -1386,7 +1340,7 @@
 
         // skip spaces
         int c = fCurrentEntity.ch[fCurrentEntity.position];
-
+        int offset = fCurrentEntity.position - 1;
         // External --  Match: S + 0x85 + 0x2028, and perform end of line normalization
         if (fCurrentEntity.isExternal()) {
             if (XML11Char.isXML11Space(c)) {
@@ -1422,6 +1376,11 @@
                     else {
                         fCurrentEntity.columnNumber++;
                     }
+
+                    //If this is a general entity, spaces within a start element should be counted
+                    checkEntityLimit(null, fCurrentEntity, offset, fCurrentEntity.position - offset);
+                    offset = fCurrentEntity.position;
+
                     // load more characters, if needed
                     if (!entityChanged)
                         fCurrentEntity.position++;
@@ -1462,6 +1421,11 @@
                 else {
                     fCurrentEntity.columnNumber++;
                 }
+
+                //If this is a general entity, spaces within a start element should be counted
+                checkEntityLimit(null, fCurrentEntity, offset, fCurrentEntity.position - offset);
+                offset = fCurrentEntity.position;
+
                 // load more characters, if needed
                 if (!entityChanged)
                     fCurrentEntity.position++;
@@ -1495,7 +1459,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public boolean skipString(String s) throws IOException {
+    protected boolean skipString(String s) throws IOException {
 
         // load more characters, if needed
         if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -1504,6 +1468,7 @@
 
         // skip string
         final int length = s.length();
+        final int beforeSkip = fCurrentEntity.position ;
         for (int i = 0; i < length; i++) {
             char c = fCurrentEntity.ch[fCurrentEntity.position++];
             if (c != s.charAt(i)) {
@@ -1523,6 +1488,9 @@
             }
         }
         fCurrentEntity.columnNumber += length;
+        if (!detectingVersion) {
+            checkEntityLimit(null, fCurrentEntity, beforeSkip, length);
+        }
         return true;
 
     } // skipString(String):boolean
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11NSDocumentScannerImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11NSDocumentScannerImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -135,7 +135,7 @@
         if (DEBUG_START_END_ELEMENT)
             System.out.println(">>> scanStartElementNS()");
                 // Note: namespace processing is on by default
-        fEntityScanner.scanQName(fElementQName);
+        fEntityScanner.scanQName(fElementQName, NameType.ATTRIBUTE);
         // REVISIT - [Q] Why do we need this local variable? -- mrglavas
         String rawname = fElementQName.rawname;
         if (fBindNamespaces) {
@@ -173,11 +173,11 @@
             // end tag?
             int c = fEntityScanner.peekChar();
             if (c == '>') {
-                fEntityScanner.scanChar();
+                fEntityScanner.scanChar(null);
                 break;
             } else if (c == '/') {
-                fEntityScanner.scanChar();
-                if (!fEntityScanner.skipChar('>')) {
+                fEntityScanner.scanChar(null);
+                if (!fEntityScanner.skipChar('>', null)) {
                     reportFatalError(
                         "ElementUnterminated",
                         new Object[] { rawname });
@@ -345,7 +345,7 @@
     protected void scanStartElementName ()
         throws IOException, XNIException {
         // Note: namespace processing is on by default
-        fEntityScanner.scanQName(fElementQName);
+        fEntityScanner.scanQName(fElementQName, NameType.ATTRIBUTE);
         // Must skip spaces here because the DTD scanner
         // would consume them at the end of the external subset.
         fSawSpace = fEntityScanner.skipSpaces();
@@ -395,11 +395,11 @@
             // end tag?
             int c = fEntityScanner.peekChar();
             if (c == '>') {
-                fEntityScanner.scanChar();
+                fEntityScanner.scanChar(null);
                 break;
             } else if (c == '/') {
-                fEntityScanner.scanChar();
-                if (!fEntityScanner.skipChar('>')) {
+                fEntityScanner.scanChar(null);
+                if (!fEntityScanner.skipChar('>', null)) {
                     reportFatalError(
                         "ElementUnterminated",
                         new Object[] { rawname });
@@ -571,11 +571,11 @@
             System.out.println(">>> scanAttribute()");
 
         // name
-        fEntityScanner.scanQName(fAttributeQName);
+        fEntityScanner.scanQName(fAttributeQName, NameType.ATTRIBUTE);
 
         // equals
         fEntityScanner.skipSpaces();
-        if (!fEntityScanner.skipChar('=')) {
+        if (!fEntityScanner.skipChar('=', NameType.ATTRIBUTE)) {
             reportFatalError(
                 "EqRequiredInAttribute",
                 new Object[] {
@@ -614,13 +614,20 @@
         //REVISIT: one more case needs to be included: external PE and standalone is no
         boolean isVC = fHasExternalDTD && !fStandalone;
 
-        // REVISIT: it seems that this function should not take attributes, and length
-        scanAttributeValue(
-            this.fTempString,
-            fTempString2,
-            fAttributeQName.rawname,
-            isVC,
-            fCurrentElement.rawname);
+        /**
+         * Determine whether this is a namespace declaration that will be subject
+         * to the name limit check in the scanAttributeValue operation.
+         * Namespace declaration format: xmlns="..." or xmlns:prefix="..."
+         * Note that prefix:xmlns="..." isn't a namespace.
+         */
+        String localpart = fAttributeQName.localpart;
+        String prefix = fAttributeQName.prefix != null
+                ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
+        boolean isNSDecl = fBindNamespaces & (prefix == XMLSymbols.PREFIX_XMLNS ||
+                    prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS);
+
+        scanAttributeValue(this.fTempString, fTempString2, fAttributeQName.rawname,
+            isVC, fCurrentElement.rawname, isNSDecl);
         String value = fTempString.toString();
         attributes.setValue(attrIndex, value);
         attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
@@ -628,17 +635,7 @@
 
         // record namespace declarations if any.
         if (fBindNamespaces) {
-
-            String localpart = fAttributeQName.localpart;
-            String prefix =
-                fAttributeQName.prefix != null
-                    ? fAttributeQName.prefix
-                    : XMLSymbols.EMPTY_STRING;
-            // when it's of form xmlns="..." or xmlns:prefix="...",
-            // it's a namespace declaration. but prefix:xmlns="..." isn't.
-            if (prefix == XMLSymbols.PREFIX_XMLNS
-                || prefix == XMLSymbols.EMPTY_STRING
-                && localpart == XMLSymbols.PREFIX_XMLNS) {
+            if (isNSDecl) {
                 if (value.length() > fXMLNameLimit) {
                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
                             "MaxXMLNameLimit",
@@ -758,7 +755,7 @@
 
         // end
         fEntityScanner.skipSpaces();
-        if (!fEntityScanner.skipChar('>')) {
+        if (!fEntityScanner.skipChar('>', NameType.ELEMENTEND)) {
             reportFatalError(
                 "ETagUnterminated",
                 new Object[] { endElementName.rawname });
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -21,10 +21,7 @@
 
 package com.sun.org.apache.xerces.internal.impl;
 
-import com.sun.org.apache.xerces.internal.impl.Constants;
 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
-import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
-import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
 import com.sun.org.apache.xerces.internal.util.SymbolTable;
 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
 import com.sun.org.apache.xerces.internal.util.XMLChar;
@@ -367,6 +364,7 @@
                 // we're done, set starting state for external subset
                 setScannerState(SCANNER_STATE_TEXT_DECL);
                 // we're done scanning DTD.
+                fLimitAnalyzer.reset(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT);
                 fLimitAnalyzer.reset(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT);
                 return false;
             }
@@ -399,7 +397,7 @@
                 if (isInvalidLiteral(c)) {
                     reportFatalError("InvalidCharInDTD",
                         new Object[] { Integer.toHexString(c) });
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                 }
             }
         }
@@ -767,7 +765,7 @@
                 fStringBuffer.clear();
                 fStringBuffer.append("xml");
                 while (isValidNameChar(fEntityScanner.peekChar())) {
-                    fStringBuffer.append((char)fEntityScanner.scanChar());
+                    fStringBuffer.append((char)fEntityScanner.scanChar(null));
                 }
                 String target =
                 fSymbolTable.addSymbol(fStringBuffer.ch,
@@ -867,7 +865,7 @@
         }
 
         // element name
-        String name = fEntityScanner.scanName();
+        String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
         if (name == null) {
             reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL",
             null);
@@ -900,7 +898,7 @@
             }
         }
         else {
-            if (!fEntityScanner.skipChar('(')) {
+            if (!fEntityScanner.skipChar('(', null)) {
                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
                 new Object[]{name});
             }
@@ -930,7 +928,7 @@
         fReportEntity = false;
         skipSeparator(false, !scanningInternalSubset());
         // end
-        if (!fEntityScanner.skipChar('>')) {
+        if (!fEntityScanner.skipChar('>', null)) {
             reportFatalError("ElementDeclUnterminated", new Object[]{name});
         }
         fReportEntity = true;
@@ -967,7 +965,7 @@
             fDTDContentModelHandler.pcdata(null);
         }
         skipSeparator(false, !scanningInternalSubset());
-        while (fEntityScanner.skipChar('|')) {
+        while (fEntityScanner.skipChar('|', null)) {
             fStringBuffer.append('|');
             // call handler
             if (fDTDContentModelHandler != null) {
@@ -976,7 +974,7 @@
             }
             skipSeparator(false, !scanningInternalSubset());
 
-            childName = fEntityScanner.scanName();
+            childName = fEntityScanner.scanName(NameType.ENTITY);
             if (childName == null) {
                 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
                 new Object[]{elName});
@@ -1005,7 +1003,7 @@
             reportFatalError("MixedContentUnterminated",
             new Object[]{elName});
         }
-        else if (fEntityScanner.skipChar(')')){
+        else if (fEntityScanner.skipChar(')', null)){
             fStringBuffer.append(')');
             // call handler
             if (fDTDContentModelHandler != null) {
@@ -1043,7 +1041,7 @@
         int currentOp = 0;
         int c;
         while (true) {
-            if (fEntityScanner.skipChar('(')) {
+            if (fEntityScanner.skipChar('(', null)) {
                 fMarkUpDepth++;
                 fStringBuffer.append('(');
                 // call handler
@@ -1057,7 +1055,7 @@
                 continue;
             }
             skipSeparator(false, !scanningInternalSubset());
-            String childName = fEntityScanner.scanName();
+            String childName = fEntityScanner.scanName(NameType.ELEMENTSTART);
             if (childName == null) {
                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
                 new Object[]{elName});
@@ -1084,7 +1082,7 @@
                     }
                     fDTDContentModelHandler.occurrence(oc, null);
                 }
-                fEntityScanner.scanChar();
+                fEntityScanner.scanChar(null);
                 fStringBuffer.append((char)c);
             }
             while (true) {
@@ -1097,7 +1095,7 @@
                         fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
                         null);
                     }
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     fStringBuffer.append(',');
                     break;
                 }
@@ -1108,7 +1106,7 @@
                         fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
                         null);
                     }
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     fStringBuffer.append('|');
                     break;
                 }
@@ -1154,7 +1152,7 @@
                 }
                 else {
                     // no occurrence specified
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     fStringBuffer.append(')');
                 }
                 fMarkUpDepth--;
@@ -1186,7 +1184,7 @@
         }
 
         // element name
-        String elName = fEntityScanner.scanName();
+        String elName = fEntityScanner.scanName(NameType.ELEMENTSTART);
         if (elName == null) {
             reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL",
             null);
@@ -1200,7 +1198,7 @@
         // spaces
         if (!skipSeparator(true, !scanningInternalSubset())) {
             // no space, is it the end yet?
-            if (fEntityScanner.skipChar('>')) {
+            if (fEntityScanner.skipChar('>', null)) {
                 // yes, stop here
                 // call handler
                 if (fDTDHandler != null) {
@@ -1216,8 +1214,8 @@
         }
 
         // definitions
-        while (!fEntityScanner.skipChar('>')) {
-            String name = fEntityScanner.scanName();
+        while (!fEntityScanner.skipChar('>', null)) {
+            String name = fEntityScanner.scanName(NameType.ATTRIBUTE);
             if (name == null) {
                 reportFatalError("AttNameRequiredInAttDef",
                 new Object[]{elName});
@@ -1353,7 +1351,7 @@
                 new Object[]{elName, atName});
             }
             // open paren
-            int c = fEntityScanner.scanChar();
+            int c = fEntityScanner.scanChar(null);
             if (c != '(') {
                 reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
                 new Object[]{elName, atName});
@@ -1361,7 +1359,7 @@
             fMarkUpDepth++;
             do {
                 skipSeparator(false, !scanningInternalSubset());
-                String aName = fEntityScanner.scanName();
+                String aName = fEntityScanner.scanName(NameType.ATTRIBUTE);
                 if (aName == null) {
                     reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
                     new Object[]{elName, atName});
@@ -1369,7 +1367,7 @@
                 ensureEnumerationSize(fEnumerationCount + 1);
                 fEnumeration[fEnumerationCount++] = aName;
                 skipSeparator(false, !scanningInternalSubset());
-                c = fEntityScanner.scanChar();
+                c = fEntityScanner.scanChar(null);
             } while (c == '|');
             if (c != ')') {
                 reportFatalError("NotationTypeUnterminated",
@@ -1380,7 +1378,7 @@
         else {              // Enumeration
             type = "ENUMERATION";
             // open paren
-            int c = fEntityScanner.scanChar();
+            int c = fEntityScanner.scanChar(null);
             if (c != '(') {
                 //                       "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
                 reportFatalError("AttTypeRequiredInAttDef",
@@ -1397,7 +1395,7 @@
                 ensureEnumerationSize(fEnumerationCount + 1);
                 fEnumeration[fEnumerationCount++] = token;
                 skipSeparator(false, !scanningInternalSubset());
-                c = fEntityScanner.scanChar();
+                c = fEntityScanner.scanChar(null);
             } while (c == '|');
             if (c != ')') {
                 reportFatalError("EnumerationUnterminated",
@@ -1447,7 +1445,7 @@
             // AttValue
             boolean isVC = !fStandalone  &&  (fSeenExternalDTD || fSeenExternalPE) ;
             scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName,
-            fAttributes, 0, isVC, elName);
+            fAttributes, 0, isVC, elName, false);
         }
         return defaultType;
 
@@ -1475,7 +1473,7 @@
         boolean sawPERef = false;
         fReportEntity = false;
         if (fEntityScanner.skipSpaces()) {
-            if (!fEntityScanner.skipChar('%')) {
+            if (!fEntityScanner.skipChar('%', NameType.REFERENCE)) {
                 isPEDecl = false; // <!ENTITY x "x">
             }
             else if (skipSeparator(true, !scanningInternalSubset())) {
@@ -1496,7 +1494,7 @@
                 sawPERef = true;
             }
         }
-        else if (scanningInternalSubset() || !fEntityScanner.skipChar('%')) {
+        else if (scanningInternalSubset() || !fEntityScanner.skipChar('%', NameType.REFERENCE)) {
             // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
             null);
@@ -1513,11 +1511,11 @@
         }
         if (sawPERef) {
             while (true) {
-                String peName = fEntityScanner.scanName();
+                String peName = fEntityScanner.scanName(NameType.REFERENCE);
                 if (peName == null) {
                     reportFatalError("NameRequiredInPEReference", null);
                 }
-                else if (!fEntityScanner.skipChar(';')) {
+                else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
                     reportFatalError("SemicolonRequiredInPEReference",
                     new Object[]{peName});
                 }
@@ -1525,20 +1523,20 @@
                     startPE(peName, false);
                 }
                 fEntityScanner.skipSpaces();
-                if (!fEntityScanner.skipChar('%'))
+                if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
                     break;
                 if (!isPEDecl) {
                     if (skipSeparator(true, !scanningInternalSubset())) {
                         isPEDecl = true;
                         break;
                     }
-                    isPEDecl = fEntityScanner.skipChar('%');
+                    isPEDecl = fEntityScanner.skipChar('%', NameType.REFERENCE);
                 }
             }
         }
 
         // name
-        String name = fEntityScanner.scanName();
+        String name = fEntityScanner.scanName(NameType.ENTITY);
         if (name == null) {
             reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null);
         }
@@ -1573,7 +1571,7 @@
                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
                 new Object[]{name});
             }
-            notation = fEntityScanner.scanName();
+            notation = fEntityScanner.scanName(NameType.NOTATION);
             if (notation == null) {
                 reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
                 new Object[]{name});
@@ -1595,7 +1593,7 @@
         skipSeparator(false, !scanningInternalSubset());
 
         // end
-        if (!fEntityScanner.skipChar('>')) {
+        if (!fEntityScanner.skipChar('>', null)) {
             reportFatalError("EntityDeclUnterminated", new Object[]{name});
         }
         fMarkUpDepth--;
@@ -1650,7 +1648,7 @@
     protected final void scanEntityValue(String entityName, boolean isPEDecl, XMLString value,
     XMLString nonNormalizedValue)
     throws IOException, XNIException {
-        int quote = fEntityScanner.scanChar();
+        int quote = fEntityScanner.scanChar(null);
         if (quote != '\'' && quote != '"') {
             reportFatalError("OpenQuoteMissingInDecl", null);
         }
@@ -1665,23 +1663,24 @@
          }
         fLimitAnalyzer.startEntity(entityName);
 
-        if (fEntityScanner.scanLiteral(quote, fString) != quote) {
+        if (fEntityScanner.scanLiteral(quote, fString, false) != quote) {
             fStringBuffer.clear();
             fStringBuffer2.clear();
+            int offset;
             do {
-                checkEntityLimit(isPEDecl, entityName, fString.length + countChar);
                 countChar = 0;
+                offset = fStringBuffer.length;
                 fStringBuffer.append(fString);
                 fStringBuffer2.append(fString);
-                if (fEntityScanner.skipChar('&')) {
-                    if (fEntityScanner.skipChar('#')) {
+                if (fEntityScanner.skipChar('&', NameType.REFERENCE)) {
+                    if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
                         fStringBuffer2.append("&#");
                         scanCharReferenceValue(fStringBuffer, fStringBuffer2);
                     }
                     else {
                         fStringBuffer.append('&');
                         fStringBuffer2.append('&');
-                        String eName = fEntityScanner.scanName();
+                        String eName = fEntityScanner.scanName(NameType.REFERENCE);
                         if (eName == null) {
                             reportFatalError("NameRequiredInReference",
                             null);
@@ -1690,7 +1689,7 @@
                             fStringBuffer.append(eName);
                             fStringBuffer2.append(eName);
                         }
-                        if (!fEntityScanner.skipChar(';')) {
+                        if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
                             reportFatalError("SemicolonRequiredInReference",
                             new Object[]{eName});
                         }
@@ -1700,15 +1699,15 @@
                         }
                     }
                 }
-                else if (fEntityScanner.skipChar('%')) {
+                else if (fEntityScanner.skipChar('%', NameType.REFERENCE)) {
                     while (true) {
                         fStringBuffer2.append('%');
-                        String peName = fEntityScanner.scanName();
+                        String peName = fEntityScanner.scanName(NameType.REFERENCE);
                         if (peName == null) {
                             reportFatalError("NameRequiredInPEReference",
                             null);
                         }
-                        else if (!fEntityScanner.skipChar(';')) {
+                        else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
                             reportFatalError("SemicolonRequiredInPEReference",
                             new Object[]{peName});
                         }
@@ -1725,20 +1724,20 @@
                         // REVISIT: This will make returning the non-
                         //          normalized value harder. -Ac
                         fEntityScanner.skipSpaces();
-                        if (!fEntityScanner.skipChar('%'))
+                        if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
                             break;
                     }
                 }
                 else {
-                    countChar++;
                     int c = fEntityScanner.peekChar();
                     if (XMLChar.isHighSurrogate(c)) {
+                        countChar++;
                         scanSurrogates(fStringBuffer2);
                     }
                     else if (isInvalidLiteral(c)) {
                         reportFatalError("InvalidCharInLiteral",
                         new Object[]{Integer.toHexString(c)});
-                        fEntityScanner.scanChar();
+                        fEntityScanner.scanChar(null);
                     }
                     // if it's not the delimiting quote or if it is but from a
                     // different entity than the one this literal started from,
@@ -1746,10 +1745,12 @@
                     else if (c != quote || entityDepth != fEntityDepth) {
                         fStringBuffer.append((char)c);
                         fStringBuffer2.append((char)c);
-                        fEntityScanner.scanChar();
+                        fEntityScanner.scanChar(null);
                     }
                 }
-            } while (fEntityScanner.scanLiteral(quote, fString) != quote);
+                checkEntityLimit(isPEDecl, entityName, fStringBuffer.length - offset + countChar);
+            } while (fEntityScanner.scanLiteral(quote, fString, false) != quote);
+            checkEntityLimit(isPEDecl, entityName, fString.length);
             fStringBuffer.append(fString);
             fStringBuffer2.append(fString);
             literal = fStringBuffer;
@@ -1760,10 +1761,14 @@
         value.setValues(literal);
         nonNormalizedValue.setValues(literal2);
         if (fLimitAnalyzer != null) {
-            fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName);
+            if (isPEDecl) {
+                fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName);
+            } else {
+                fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName);
+            }
         }
 
-        if (!fEntityScanner.skipChar(quote)) {
+        if (!fEntityScanner.skipChar(quote, null)) {
             reportFatalError("CloseQuoteMissingInDecl", null);
         }
     } // scanEntityValue(XMLString,XMLString):void
@@ -1788,7 +1793,7 @@
         }
 
         // notation name
-        String name = fEntityScanner.scanName();
+        String name = fEntityScanner.scanName(NameType.NOTATION);
         if (name == null) {
             reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
             null);
@@ -1815,7 +1820,7 @@
         skipSeparator(false, !scanningInternalSubset());
 
         // end
-        if (!fEntityScanner.skipChar('>')) {
+        if (!fEntityScanner.skipChar('>', null)) {
             reportFatalError("NotationDeclUnterminated", new Object[]{name});
         }
         fMarkUpDepth--;
@@ -1863,7 +1868,7 @@
                 XMLErrorReporter.SEVERITY_ERROR);
             }
             // call handler
-            if (!fEntityScanner.skipChar('[')) {
+            if (!fEntityScanner.skipChar('[', null)) {
                 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
             }
 
@@ -1888,7 +1893,7 @@
                 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE,
                 null);
             }
-            if (!fEntityScanner.skipChar('[')) {
+            if (!fEntityScanner.skipChar('[', null)) {
                 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
             }
             fReportEntity = true;
@@ -1897,7 +1902,7 @@
                 fIgnoreConditionalBuffer.clear();
             }
             while (true) {
-                if (fEntityScanner.skipChar('<')) {
+                if (fEntityScanner.skipChar('<', null)) {
                     if (fDTDHandler != null) {
                         fIgnoreConditionalBuffer.append('<');
                     }
@@ -1905,8 +1910,8 @@
                     // These tests are split so that we handle cases like
                     // '<<![' and '<!<![' which we might otherwise miss.
                     //
-                    if (fEntityScanner.skipChar('!')) {
-                        if(fEntityScanner.skipChar('[')) {
+                    if (fEntityScanner.skipChar('!', null)) {
+                        if(fEntityScanner.skipChar('[', null)) {
                             if (fDTDHandler != null) {
                                 fIgnoreConditionalBuffer.append("![");
                             }
@@ -1918,24 +1923,24 @@
                         }
                     }
                 }
-                else if (fEntityScanner.skipChar(']')) {
+                else if (fEntityScanner.skipChar(']', null)) {
                     if (fDTDHandler != null) {
                         fIgnoreConditionalBuffer.append(']');
                     }
                     //
                     // The same thing goes for ']<![' and '<]]>', etc.
                     //
-                    if (fEntityScanner.skipChar(']')) {
+                    if (fEntityScanner.skipChar(']', null)) {
                         if (fDTDHandler != null) {
                             fIgnoreConditionalBuffer.append(']');
                         }
-                        while (fEntityScanner.skipChar(']')) {
+                        while (fEntityScanner.skipChar(']', null)) {
                             /* empty loop body */
                             if (fDTDHandler != null) {
                                 fIgnoreConditionalBuffer.append(']');
                             }
                         }
-                        if (fEntityScanner.skipChar('>')) {
+                        if (fEntityScanner.skipChar('>', null)) {
                             if (fIncludeSectDepth-- == initialDepth) {
                                 fMarkUpDepth--;
                                 // call handler
@@ -1953,7 +1958,7 @@
                     }
                 }
                 else {
-                    int c = fEntityScanner.scanChar();
+                    int c = fEntityScanner.scanChar(null);
                     if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
                         reportFatalError("IgnoreSectUnterminated", null);
                         return;
@@ -1990,16 +1995,16 @@
         //System.out.println("scanDecls"+fScannerState);
         while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
             again = complete;
-            if (fEntityScanner.skipChar('<')) {
+            if (fEntityScanner.skipChar('<', null)) {
                 fMarkUpDepth++;
-                if (fEntityScanner.skipChar('?')) {
+                if (fEntityScanner.skipChar('?', null)) {
                     fStringBuffer.clear();
                     scanPI(fStringBuffer);
                     fMarkUpDepth--; // we're done with this decl
                 }
-                else if (fEntityScanner.skipChar('!')) {
-                    if (fEntityScanner.skipChar('-')) {
-                        if (!fEntityScanner.skipChar('-')) {
+                else if (fEntityScanner.skipChar('!', null)) {
+                    if (fEntityScanner.skipChar('-', null)) {
+                        if (!fEntityScanner.skipChar('-', null)) {
                             reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
                             null);
                         } else {
@@ -2018,7 +2023,7 @@
                     else if (fEntityScanner.skipString("NOTATION")) {
                         scanNotationDecl();
                     }
-                    else if (fEntityScanner.skipChar('[') &&
+                    else if (fEntityScanner.skipChar('[', null) &&
                     !scanningInternalSubset()) {
                         scanConditionalSect(fPEDepth);
                     }
@@ -2033,10 +2038,10 @@
                     reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
                 }
             }
-            else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) {
+            else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']', null)) {
                 // end of conditional section?
-                if (!fEntityScanner.skipChar(']')
-                || !fEntityScanner.skipChar('>')) {
+                if (!fEntityScanner.skipChar(']', null)
+                || !fEntityScanner.skipChar('>', null)) {
                     reportFatalError("IncludeSectUnterminated", null);
                 }
                 // call handler
@@ -2083,21 +2088,21 @@
     throws IOException, XNIException {
         int depth = fPEDepth;
         boolean sawSpace = fEntityScanner.skipSpaces();
-        if (!lookForPERefs || !fEntityScanner.skipChar('%')) {
+        if (!lookForPERefs || !fEntityScanner.skipChar('%', NameType.REFERENCE)) {
             return !spaceRequired || sawSpace || (depth != fPEDepth);
         }
         while (true) {
-            String name = fEntityScanner.scanName();
+            String name = fEntityScanner.scanName(NameType.ENTITY);
             if (name == null) {
                 reportFatalError("NameRequiredInPEReference", null);
             }
-            else if (!fEntityScanner.skipChar(';')) {
+            else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
                 reportFatalError("SemicolonRequiredInPEReference",
                 new Object[]{name});
             }
             startPE(name, false);
             fEntityScanner.skipSpaces();
-            if (!fEntityScanner.skipChar('%'))
+            if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
                 return true;
         }
     }
@@ -2181,56 +2186,6 @@
         fSecurityManager = fEntityManager.fSecurityManager;
     }
 
-    /**
-     * Add the count of the content buffer and check if the accumulated
-     * value exceeds the limit
-     * @param isPEDecl a flag to indicate whether the entity is parameter
-     * @param entityName entity name
-     * @param buffer content buffer
-     */
-    private void checkEntityLimit(boolean isPEDecl, String entityName, XMLString buffer) {
-        checkEntityLimit(isPEDecl, entityName, buffer.length);
-    }
-
-    /**
-     * Add the count and check limit
-     * @param isPEDecl a flag to indicate whether the entity is parameter
-     * @param entityName entity name
-     * @param len length of the buffer
-     */
-    private void checkEntityLimit(boolean isPEDecl, String entityName, int len) {
-        if (fLimitAnalyzer == null) {
-            fLimitAnalyzer = fEntityManager.fLimitAnalyzer;
-        }
-        if (isPEDecl) {
-            fLimitAnalyzer.addValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, "%" + entityName, len);
-            if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
-                        fSecurityManager.debugPrint(fLimitAnalyzer);
-                reportFatalError("MaxEntitySizeLimit", new Object[]{"%" + entityName,
-                    fLimitAnalyzer.getValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
-                    fSecurityManager.getLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
-                    fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT)});
-            }
-        } else {
-            fLimitAnalyzer.addValue(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName, len);
-            if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
-                        fSecurityManager.debugPrint(fLimitAnalyzer);
-                reportFatalError("MaxEntitySizeLimit", new Object[]{entityName,
-                    fLimitAnalyzer.getValue(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT),
-                    fSecurityManager.getLimit(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT),
-                    fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT)});
-            }
-        }
-        if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
-            fSecurityManager.debugPrint(fLimitAnalyzer);
-            reportFatalError("TotalEntitySizeLimit",
-                new Object[]{fLimitAnalyzer.getTotalValue(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
-                fSecurityManager.getLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
-                fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT)});
-        }
-
-    }
-
     public DTDGrammar getGrammar(){
         return nvGrammarInfo;
     }
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -21,14 +21,6 @@
 
 package com.sun.org.apache.xerces.internal.impl;
 
-import com.sun.xml.internal.stream.XMLBufferListener;
-import com.sun.xml.internal.stream.XMLEntityStorage;
-import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
-
-import java.io.EOFException;
-import java.io.IOException;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.events.XMLEvent;
 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
 import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
 import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
@@ -47,13 +39,18 @@
 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentScanner;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
 import com.sun.org.apache.xerces.internal.xni.Augmentations;
-import com.sun.org.apache.xerces.internal.impl.Constants;
-import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
 import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager.Limit;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
+import com.sun.xml.internal.stream.XMLBufferListener;
+import com.sun.xml.internal.stream.XMLEntityStorage;
+import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
+import java.io.EOFException;
+import java.io.IOException;
+import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.events.XMLEvent;
 
 /**
  *
@@ -454,6 +451,7 @@
                     //fDocumentHandler.startElement(getElementQName(),fAttributes,null);
                     break;
                 case XMLStreamConstants.CHARACTERS :
+                    fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
                     fDocumentHandler.characters(getCharacterData(),null);
                     break;
                 case XMLStreamConstants.SPACE:
@@ -462,13 +460,15 @@
                     //fDocumentHandler.ignorableWhitespace(getCharacterData(), null);
                     break;
                 case XMLStreamConstants.ENTITY_REFERENCE :
+                    fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
                     //entity reference callback are given in startEntity
                     break;
                 case XMLStreamConstants.PROCESSING_INSTRUCTION :
+                    fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
                     fDocumentHandler.processingInstruction(getPITarget(),getPIData(),null);
                     break;
                 case XMLStreamConstants.COMMENT :
-                    //System.out.println(" in COMMENT of the XMLNSDocumentScannerImpl");
+                    fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
                     fDocumentHandler.comment(getCharacterData(),null);
                     break;
                 case XMLStreamConstants.DTD :
@@ -477,6 +477,7 @@
                     //therefore we don't need to take care of anything here. So Just break;
                     break;
                 case XMLStreamConstants.CDATA:
+                    fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
                     fDocumentHandler.startCDATA(null);
                     //xxx: check if CDATA values comes from getCharacterData() function
                     fDocumentHandler.characters(getCharacterData(),null);
@@ -1273,9 +1274,9 @@
             fElementQName = fElementStack.nextElement();
             // name
             if (fNamespaces) {
-                fEntityScanner.scanQName(fElementQName);
+                fEntityScanner.scanQName(fElementQName, NameType.ELEMENTSTART);
             } else {
-                String name = fEntityScanner.scanName();
+                String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
                 fElementQName.setValues(null, name, name, null);
             }
 
@@ -1376,11 +1377,11 @@
         // end tag?
         final int c = fEntityScanner.peekChar();
         if (c == '>') {
-            fEntityScanner.scanChar();
+            fEntityScanner.scanChar(null);
             return true;
         } else if (c == '/') {
-            fEntityScanner.scanChar();
-            if (!fEntityScanner.skipChar('>')) {
+            fEntityScanner.scanChar(null);
+            if (!fEntityScanner.skipChar('>', NameType.ELEMENTEND)) {
                 reportFatalError("ElementUnterminated",
                         new Object[]{fElementQName.rawname});
             }
@@ -1518,15 +1519,15 @@
 
         // name
         if (fNamespaces) {
-            fEntityScanner.scanQName(fAttributeQName);
+            fEntityScanner.scanQName(fAttributeQName, NameType.ATTRIBUTENAME);
         } else {
-            String name = fEntityScanner.scanName();
+            String name = fEntityScanner.scanName(NameType.ATTRIBUTENAME);
             fAttributeQName.setValues(null, name, name, null);
         }
 
         // equals
         fEntityScanner.skipSpaces();
-        if (!fEntityScanner.skipChar('=')) {
+        if (!fEntityScanner.skipChar('=', NameType.ATTRIBUTE)) {
             reportFatalError("EqRequiredInAttribute",
                 new Object[] {fCurrentElement.rawname, fAttributeQName.rawname});
         }
@@ -1544,9 +1545,8 @@
         //can safely add the attribute later..
         XMLString tmpStr = getString();
 
-        scanAttributeValue(tmpStr, fTempString2,
-                fAttributeQName.rawname, attributes,
-                attIndex, isVC, fCurrentElement.rawname);
+        scanAttributeValue(tmpStr, fTempString2, fAttributeQName.rawname, attributes,
+                attIndex, isVC, fCurrentElement.rawname, false);
 
         // content
         int oldLen = attributes.getLength();
@@ -1594,13 +1594,13 @@
         if (c == '\r') {
             // happens when there is the character reference &#13;
             //xxx: We know the next chracter.. we should just skip it and add ']' directlry
-            fEntityScanner.scanChar();
+            fEntityScanner.scanChar(null);
             content.append((char)c);
             c = -1;
         } else if (c == ']') {
             //fStringBuffer.clear();
             //xxx: We know the next chracter.. we should just skip it and add ']' directlry
-            content.append((char)fEntityScanner.scanChar());
+            content.append((char)fEntityScanner.scanChar(null));
             // remember where we are in case we get an endEntity before we
             // could flush the buffer out - this happens when we're parsing an
             // entity which ends with a ]
@@ -1609,12 +1609,12 @@
             // We work on a single character basis to handle cases such as:
             // ']]]>' which we might otherwise miss.
             //
-            if (fEntityScanner.skipChar(']')) {
+            if (fEntityScanner.skipChar(']', null)) {
                 content.append(']');
-                while (fEntityScanner.skipChar(']')) {
+                while (fEntityScanner.skipChar(']', null)) {
                     content.append(']');
                 }
-                if (fEntityScanner.skipChar('>')) {
+                if (fEntityScanner.skipChar('>', null)) {
                     reportFatalError("CDEndInContent", null);
                 }
             }
@@ -1689,7 +1689,7 @@
                     } else {
                         reportFatalError("InvalidCharInCDSect",
                                 new Object[]{Integer.toString(c,16)});
-                                fEntityScanner.scanChar();
+                                fEntityScanner.scanChar(null);
                     }
                 }
                 //by this time we have also read surrogate contents if any...
@@ -1751,7 +1751,7 @@
 
         // end
         fEntityScanner.skipSpaces();
-        if (!fEntityScanner.skipChar('>')) {
+        if (!fEntityScanner.skipChar('>', NameType.ELEMENTEND)) {
             reportFatalError("ETagUnterminated",
                     new Object[]{rawname});
         }
@@ -1841,12 +1841,12 @@
      *                      notification.
      */
     protected void scanEntityReference(XMLStringBuffer content) throws IOException, XNIException {
-        String name = fEntityScanner.scanName();
+        String name = fEntityScanner.scanName(NameType.REFERENCE);
         if (name == null) {
             reportFatalError("NameRequiredInReference", null);
             return;
         }
-        if (!fEntityScanner.skipChar(';')) {
+        if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
             reportFatalError("SemicolonRequiredInReference", new Object []{name});
         }
         if (fEntityStore.isUnparsedEntity(name)) {
@@ -1943,6 +1943,7 @@
      */
     private void handleCharacter(char c, String entity, XMLStringBuffer content) throws XNIException {
         foundBuiltInRefs = true;
+        checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
         content.append(c);
         if (fDocumentHandler != null) {
             fSingleChar[0] = c;
@@ -2608,13 +2609,13 @@
                 switch(ch){
                     case '?' :{
                         setScannerState(SCANNER_STATE_PI);
-                        fEntityScanner.skipChar(ch);
+                        fEntityScanner.skipChar(ch, null);
                         break;
                     }
                     case '!' :{
-                        fEntityScanner.skipChar(ch);
-                        if (fEntityScanner.skipChar('-')) {
-                            if (!fEntityScanner.skipChar('-')) {
+                        fEntityScanner.skipChar(ch, null);
+                        if (fEntityScanner.skipChar('-', null)) {
+                            if (!fEntityScanner.skipChar('-', NameType.COMMENT)) {
                                 reportFatalError("InvalidCommentStart",
                                         null);
                             }
@@ -2629,7 +2630,7 @@
                     }
                     case '/' :{
                         setScannerState(SCANNER_STATE_END_ELEMENT_TAG);
-                        fEntityScanner.skipChar(ch);
+                        fEntityScanner.skipChar(ch, NameType.ELEMENTEND);
                         break;
                     }
                     default :{
@@ -2641,9 +2642,9 @@
         }//startOfMarkup
 
         private void startOfContent() throws IOException {
-            if (fEntityScanner.skipChar('<')) {
+            if (fEntityScanner.skipChar('<', null)) {
                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
-            } else if (fEntityScanner.skipChar('&')) {
+            } else if (fEntityScanner.skipChar('&', NameType.REFERENCE)) {
                 setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
             } else {
                 //element content is there..
@@ -2716,10 +2717,10 @@
                     case SCANNER_STATE_CONTENT: {
                         final int ch = fEntityScanner.peekChar();
                         if (ch == '<') {
-                            fEntityScanner.scanChar();
+                            fEntityScanner.scanChar(null);
                             setScannerState(SCANNER_STATE_START_OF_MARKUP);
                         } else if (ch == '&') {
-                            fEntityScanner.scanChar();
+                            fEntityScanner.scanChar(NameType.REFERENCE);
                             setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
                             break;
                         } else {
@@ -2819,9 +2820,9 @@
                         if(DEBUG){
                             System.out.println("fTempString = " + fTempString);
                         }
-                        if(fEntityScanner.skipChar('<')){
+                        if(fEntityScanner.skipChar('<', null)){
                             //check if we have reached end of element
-                            if(fEntityScanner.skipChar('/')){
+                            if(fEntityScanner.skipChar('/', NameType.ELEMENTEND)){
                                 //increase the mark up depth
                                 fMarkupDepth++;
                                 fLastSectionWasCharacterData = false;
@@ -2871,7 +2872,7 @@
                             }
                             // happens when there is the character reference &#13;
                             //xxx: We know the next chracter.. we should just skip it and add ']' directlry
-                            fEntityScanner.scanChar();
+                            fEntityScanner.scanChar(null);
                             fUsebuffer = true;
                             fContentBuffer.append((char)c);
                             c = -1 ;
@@ -2879,7 +2880,7 @@
                             //fStringBuffer.clear();
                             //xxx: We know the next chracter.. we should just skip it and add ']' directlry
                             fUsebuffer = true;
-                            fContentBuffer.append((char)fEntityScanner.scanChar());
+                            fContentBuffer.append((char)fEntityScanner.scanChar(null));
                             // remember where we are in case we get an endEntity before we
                             // could flush the buffer out - this happens when we're parsing an
                             // entity which ends with a ]
@@ -2888,12 +2889,12 @@
                             // We work on a single character basis to handle cases such as:
                             // ']]]>' which we might otherwise miss.
                             //
-                            if (fEntityScanner.skipChar(']')) {
+                            if (fEntityScanner.skipChar(']', null)) {
                                 fContentBuffer.append(']');
-                                while (fEntityScanner.skipChar(']')) {
+                                while (fEntityScanner.skipChar(']', null)) {
                                     fContentBuffer.append(']');
                                 }
-                                if (fEntityScanner.skipChar('>')) {
+                                if (fEntityScanner.skipChar('>', null)) {
                                     reportFatalError("CDEndInContent", null);
                                 }
                             }
@@ -2906,12 +2907,12 @@
                             // we need not to grow the buffer only when isCoalesce() is not true;
 
                             if (c == '<') {
-                                fEntityScanner.scanChar();
+                                fEntityScanner.scanChar(null);
                                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
                                 break;
                             }//xxx what should be the behavior if entity reference is present in the content ?
                             else if (c == '&') {
-                                fEntityScanner.scanChar();
+                                fEntityScanner.scanChar(NameType.REFERENCE);
                                 setScannerState(SCANNER_STATE_REFERENCE);
                                 break;
                             }///xxx since this part is also characters, it should be merged...
@@ -2924,7 +2925,7 @@
                                     reportFatalError("InvalidCharInContent",
                                             new Object[] {
                                         Integer.toString(c, 16)});
-                                        fEntityScanner.scanChar();
+                                        fEntityScanner.scanChar(null);
                                 }
                                 break;
                             }
@@ -3050,7 +3051,7 @@
                         }
                         fUsebuffer = true ;
                         //take care of character reference
-                        if (fEntityScanner.skipChar('#')) {
+                        if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
                             scanCharReferenceValue(fContentBuffer, null);
                             fMarkupDepth--;
                             if(!fIsCoalesce){
@@ -3106,11 +3107,11 @@
 
                                 if (fNamespaces) {
                                     while (isValidNCName(fEntityScanner.peekChar())) {
-                                        fStringBuffer.append((char)fEntityScanner.scanChar());
+                                        fStringBuffer.append((char)fEntityScanner.scanChar(null));
                                     }
                                 } else {
                                     while (isValidNameChar(fEntityScanner.peekChar())) {
-                                        fStringBuffer.append((char)fEntityScanner.scanChar());
+                                        fStringBuffer.append((char)fEntityScanner.scanChar(null));
                                     }
                                 }
                                 String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -631,7 +631,7 @@
         }
 
         // root element name
-        fDoctypeName = fEntityScanner.scanName();
+        fDoctypeName = fEntityScanner.scanName(NameType.DOCTYPE);
         if (fDoctypeName == null) {
             reportFatalError("MSG_ROOT_ELEMENT_TYPE_REQUIRED", null);
         }
@@ -671,10 +671,10 @@
 
         // is there an internal subset?
         boolean internalSubset = true;
-        if (!fEntityScanner.skipChar('[')) {
+        if (!fEntityScanner.skipChar('[', null)) {
             internalSubset = false;
             fEntityScanner.skipSpaces();
-            if (!fEntityScanner.skipChar('>')) {
+            if (!fEntityScanner.skipChar('>', null)) {
                 reportFatalError("DoctypedeclUnterminated", new Object[]{fDoctypeName});
             }
             fMarkupDepth--;
@@ -753,7 +753,7 @@
                         fStringBuffer.clear();
                         fStringBuffer.append("xml");
                         while (XMLChar.isName(fEntityScanner.peekChar())) {
-                            fStringBuffer.append((char)fEntityScanner.scanChar());
+                            fStringBuffer.append((char)fEntityScanner.scanChar(null));
                         }
                         String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
                         //this function should fill the data.. and set the fEvent object to this event.
@@ -831,9 +831,9 @@
                     switch (fScannerState) {
                         case SCANNER_STATE_PROLOG: {
                             fEntityScanner.skipSpaces();
-                            if (fEntityScanner.skipChar('<')) {
+                            if (fEntityScanner.skipChar('<', null)) {
                                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
-                            } else if (fEntityScanner.skipChar('&')) {
+                            } else if (fEntityScanner.skipChar('&', NameType.REFERENCE)) {
                                 setScannerState(SCANNER_STATE_REFERENCE);
                             } else {
                                 setScannerState(SCANNER_STATE_CONTENT);
@@ -849,9 +849,9 @@
                                 setDriver(fContentDriver);
                                 //from now onwards this would be handled by fContentDriver,in the same next() call
                                 return fContentDriver.next();
-                            } else if (fEntityScanner.skipChar('!')) {
-                                if (fEntityScanner.skipChar('-')) {
-                                    if (!fEntityScanner.skipChar('-')) {
+                            } else if (fEntityScanner.skipChar('!', null)) {
+                                if (fEntityScanner.skipChar('-', null)) {
+                                    if (!fEntityScanner.skipChar('-', null)) {
                                         reportFatalError("InvalidCommentStart",
                                                 null);
                                     }
@@ -871,7 +871,7 @@
                                     reportFatalError("MarkupNotRecognizedInProlog",
                                             null);
                                 }
-                            } else if (fEntityScanner.skipChar('?')) {
+                            } else if (fEntityScanner.skipChar('?', null)) {
                                 setScannerState(SCANNER_STATE_PI);
                             } else {
                                 reportFatalError("MarkupNotRecognizedInProlog",
@@ -991,7 +991,7 @@
 
                     case SCANNER_STATE_CONTENT: {
                         reportFatalError("ContentIllegalInProlog", null);
-                        fEntityScanner.scanChar();
+                        fEntityScanner.scanChar(null);
                     }
                     case SCANNER_STATE_REFERENCE: {
                         reportFatalError("ReferenceIllegalInProlog", null);
@@ -1105,11 +1105,11 @@
                             fReadingDTD=false;
                             if (!moreToScan) {
                                 // end doctype declaration
-                                if (!fEntityScanner.skipChar(']')) {
+                                if (!fEntityScanner.skipChar(']', null)) {
                                     reportFatalError("DoctypedeclNotClosed", new Object[]{fDoctypeName});
                                 }
                                 fEntityScanner.skipSpaces();
-                                if (!fEntityScanner.skipChar('>')) {
+                                if (!fEntityScanner.skipChar('>', null)) {
                                     reportFatalError("DoctypedeclUnterminated", new Object[]{fDoctypeName});
                                 }
                                 fMarkupDepth--;
@@ -1373,7 +1373,7 @@
                             if(fScannerState == SCANNER_STATE_TERMINATED ){
                                 return XMLEvent.END_DOCUMENT ;
                             }
-                            if (fEntityScanner.skipChar('<')) {
+                            if (fEntityScanner.skipChar('<', null)) {
                                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
                             } else {
                                 setScannerState(SCANNER_STATE_CONTENT);
@@ -1382,11 +1382,11 @@
                         }
                         case SCANNER_STATE_START_OF_MARKUP: {
                             fMarkupDepth++;
-                            if (fEntityScanner.skipChar('?')) {
+                            if (fEntityScanner.skipChar('?', null)) {
                                 setScannerState(SCANNER_STATE_PI);
-                            } else if (fEntityScanner.skipChar('!')) {
+                            } else if (fEntityScanner.skipChar('!', null)) {
                                 setScannerState(SCANNER_STATE_COMMENT);
-                            } else if (fEntityScanner.skipChar('/')) {
+                            } else if (fEntityScanner.skipChar('/', null)) {
                                 reportFatalError("MarkupNotRecognizedInMisc",
                                         null);
                             } else if (isValidNameStartChar(fEntityScanner.peekChar()) ||
@@ -1429,7 +1429,7 @@
                         } else{
                             reportFatalError("ContentIllegalInTrailingMisc",
                                     null);
-                            fEntityScanner.scanChar();
+                            fEntityScanner.scanChar(null);
                             setScannerState(SCANNER_STATE_TRAILING_MISC);
                             return XMLEvent.CHARACTERS;
                         }
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java	Wed Jul 05 22:00:06 2017 +0200
@@ -2066,6 +2066,7 @@
 
         // system id has to be a valid URI
         if (strict) {
+
             try {
                 // if it's already an absolute one, return it
                 new URI(systemId);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java	Wed Jul 05 22:00:06 2017 +0200
@@ -21,6 +21,7 @@
 
 package com.sun.org.apache.xerces.internal.impl;
 
+import com.sun.org.apache.xerces.internal.impl.XMLScanner.NameType;
 import com.sun.org.apache.xerces.internal.impl.io.ASCIIReader;
 import com.sun.org.apache.xerces.internal.impl.io.UCSReader;
 import com.sun.org.apache.xerces.internal.impl.io.UTF8Reader;
@@ -144,6 +145,9 @@
     // so that XMLStreamReader.getVersion() can find that out.
     protected boolean xmlVersionSetExplicitly = false;
 
+    // indicates that the operation is for detecting XML version
+    boolean detectingVersion = false;
+
     //
     // Constructors
     //
@@ -530,10 +534,12 @@
      * <p>
      * <strong>Note:</strong> The character is consumed.
      *
+     * @param nt The type of the name (element or attribute)
+     *
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public int scanChar() throws IOException {
+    protected int scanChar(NameType nt) throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(scanChar: ");
             print();
@@ -546,6 +552,7 @@
         }
 
         // scan character
+        int offset = fCurrentEntity.position;
         int c = fCurrentEntity.ch[fCurrentEntity.position++];
         if (c == '\n' || (c == '\r' && isExternal)) {
             fCurrentEntity.lineNumber++;
@@ -554,6 +561,7 @@
                 invokeListeners(1);
                 fCurrentEntity.ch[0] = (char)c;
                 load(1, false, false);
+                offset = 0;
             }
             if (c == '\r' && isExternal) {
                 if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') {
@@ -570,6 +578,9 @@
             System.out.println(" -> '"+(char)c+"'");
         }
         fCurrentEntity.columnNumber++;
+        if (!detectingVersion) {
+            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
+        }
         return c;
 
     } // scanChar():int
@@ -589,7 +600,7 @@
      * @see com.sun.org.apache.xerces.internal.util.SymbolTable
      * @see com.sun.org.apache.xerces.internal.util.XMLChar#isName
      */
-    public String scanNmtoken() throws IOException {
+    protected String scanNmtoken() throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(scanNmtoken: ");
             print();
@@ -661,6 +672,8 @@
      * <strong>Note:</strong> The string returned must be a symbol. The
      * SymbolTable can be used for this purpose.
      *
+     * @param nt The type of the name (element or attribute)
+     *
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      *
@@ -668,7 +681,7 @@
      * @see com.sun.org.apache.xerces.internal.util.XMLChar#isName
      * @see com.sun.org.apache.xerces.internal.util.XMLChar#isNameStart
      */
-    public String scanName() throws IOException {
+    protected String scanName(NameType nt) throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(scanName: ");
             print();
@@ -682,6 +695,7 @@
 
         // scan name
         int offset = fCurrentEntity.position;
+        int length;
         if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) {
             if (++fCurrentEntity.position == fCurrentEntity.count) {
                 invokeListeners(1);
@@ -709,20 +723,7 @@
                     vc = XMLChar.isName(c);
                 }
                 if(!vc)break;
-                if (++fCurrentEntity.position == fCurrentEntity.count) {
-                    int length = fCurrentEntity.position - offset;
-                    invokeListeners(length);
-                    if (length == fCurrentEntity.fBufferSize) {
-                        // bad luck we have to resize our buffer
-                        char[] tmp = new char[fCurrentEntity.fBufferSize * 2];
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                tmp, 0, length);
-                        fCurrentEntity.ch = tmp;
-                        fCurrentEntity.fBufferSize *= 2;
-                    } else {
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                fCurrentEntity.ch, 0, length);
-                    }
+                if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
                     offset = 0;
                     if (load(length, false, false)) {
                         break;
@@ -730,12 +731,14 @@
                 }
             }
         }
-        int length = fCurrentEntity.position - offset;
+        length = fCurrentEntity.position - offset;
         fCurrentEntity.columnNumber += length;
 
         // return name
         String symbol;
         if (length > 0) {
+            checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
+            checkEntityLimit(nt, fCurrentEntity, offset, length);
             symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
         } else
             symbol = null;
@@ -759,6 +762,7 @@
      * this purpose.
      *
      * @param qname The qualified name structure to fill.
+     * @param nt The type of the name (element or attribute)
      *
      * @return Returns true if a qualified name appeared immediately on
      *         the input and was scanned, false otherwise.
@@ -770,7 +774,7 @@
      * @see com.sun.org.apache.xerces.internal.util.XMLChar#isName
      * @see com.sun.org.apache.xerces.internal.util.XMLChar#isNameStart
      */
-    public boolean scanQName(QName qname) throws IOException {
+    protected boolean scanQName(QName qname, NameType nt) throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(scanQName, "+qname+": ");
             print();
@@ -806,11 +810,13 @@
                         print();
                         System.out.println(" -> true");
                     }
+                    checkEntityLimit(nt, fCurrentEntity, 0, 1);
                     return true;
                 }
             }
             int index = -1;
             boolean vc = false;
+            int length;
             while ( true){
 
                 //XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) ;
@@ -829,22 +835,7 @@
                     //check prefix before further read
                     checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, index - offset);
                 }
-                if (++fCurrentEntity.position == fCurrentEntity.count) {
-                    int length = fCurrentEntity.position - offset;
-                    //check localpart before loading more data
-                    checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length - index - 1);
-                    invokeListeners(length);
-                    if (length == fCurrentEntity.fBufferSize) {
-                        // bad luck we have to resize our buffer
-                        char[] tmp = new char[fCurrentEntity.fBufferSize * 2];
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                tmp, 0, length);
-                        fCurrentEntity.ch = tmp;
-                        fCurrentEntity.fBufferSize *= 2;
-                    } else {
-                        System.arraycopy(fCurrentEntity.ch, offset,
-                                fCurrentEntity.ch, 0, length);
-                    }
+                if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
                     if (index != -1) {
                         index = index - offset;
                     }
@@ -854,7 +845,7 @@
                     }
                 }
             }
-            int length = fCurrentEntity.position - offset;
+            length = fCurrentEntity.position - offset;
             fCurrentEntity.columnNumber += length;
             if (length > 0) {
                 String prefix = null;
@@ -885,6 +876,7 @@
                     print();
                     System.out.println(" -> true");
                 }
+                checkEntityLimit(nt, fCurrentEntity, offset, length);
                 return true;
             }
         }
@@ -900,22 +892,104 @@
     } // scanQName(QName):boolean
 
     /**
+     * Checks whether the end of the entity buffer has been reached. If yes,
+     * checks against the limit and buffer size before loading more characters.
+     *
+     * @param entity the current entity
+     * @param offset the offset from which the current read was started
+     * @param nameOffset the offset from which the current name starts
+     * @return the length of characters scanned before the end of the buffer,
+     * zero if there is more to be read in the buffer
+     */
+    protected int checkBeforeLoad(Entity.ScannedEntity entity, int offset,
+            int nameOffset) throws IOException {
+        int length = 0;
+        if (++entity.position == entity.count) {
+            length = entity.position - offset;
+            int nameLength = length;
+            if (nameOffset != -1) {
+                nameOffset = nameOffset - offset;
+                nameLength = length - nameOffset;
+            } else {
+                nameOffset = offset;
+            }
+            //check limit before loading more data
+            checkLimit(Limit.MAX_NAME_LIMIT, entity, nameOffset, nameLength);
+            invokeListeners(length);
+            if (length == entity.ch.length) {
+                // bad luck we have to resize our buffer
+                char[] tmp = new char[entity.fBufferSize * 2];
+                System.arraycopy(entity.ch, offset, tmp, 0, length);
+                entity.ch = tmp;
+                entity.fBufferSize *= 2;
+            }
+            else {
+                System.arraycopy(entity.ch, offset, entity.ch, 0, length);
+            }
+        }
+        return length;
+    }
+
+    /**
+     * If the current entity is an Entity reference, check the accumulated size
+     * against the limit.
+     *
+     * @param nt type of name (element, attribute or entity)
+     * @param entity The current entity
+     * @param offset The index of the first byte
+     * @param length The length of the entity scanned
+     */
+    protected void checkEntityLimit(NameType nt, ScannedEntity entity, int offset, int length) {
+        if (entity == null || !entity.isGE) {
+            return;
+        }
+
+        if (nt != NameType.REFERENCE) {
+            checkLimit(Limit.GENERAL_ENTITY_SIZE_LIMIT, entity, offset, length);
+        }
+        if (nt == NameType.ELEMENTSTART || nt == NameType.ATTRIBUTENAME) {
+            checkNodeCount(entity);
+        }
+    }
+
+    /**
+     * If the current entity is an Entity reference, counts the total nodes in
+     * the entity and checks the accumulated value against the limit.
+     *
+     * @param entity The current entity
+     */
+    protected void checkNodeCount(ScannedEntity entity) {
+        if (entity != null && entity.isGE) {
+            checkLimit(Limit.ENTITY_REPLACEMENT_LIMIT, entity, 0, 1);
+        }
+    }
+
+    /**
      * Checks whether the value of the specified Limit exceeds its limit
      *
-     * @param limit The Limit to be checked.
-     * @param entity The current entity.
+     * @param limit The Limit to be checked
+     * @param entity The current entity
      * @param offset The index of the first byte
-     * @param length The length of the entity scanned.
+     * @param length The length of the entity scanned
      */
     protected void checkLimit(Limit limit, ScannedEntity entity, int offset, int length) {
-        fLimitAnalyzer.addValue(limit, null, length);
+        fLimitAnalyzer.addValue(limit, entity.name, length);
         if (fSecurityManager.isOverLimit(limit, fLimitAnalyzer)) {
             fSecurityManager.debugPrint(fLimitAnalyzer);
+            Object[] e = (limit == Limit.ENTITY_REPLACEMENT_LIMIT) ?
+                    new Object[]{fLimitAnalyzer.getValue(limit),
+                        fSecurityManager.getLimit(limit), fSecurityManager.getStateLiteral(limit)} :
+                    new Object[]{entity.name, fLimitAnalyzer.getValue(limit),
+                        fSecurityManager.getLimit(limit), fSecurityManager.getStateLiteral(limit)};
             fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, limit.key(),
-                    new Object[]{new String(entity.ch, offset, length),
-                fLimitAnalyzer.getTotalValue(limit),
-                fSecurityManager.getLimit(limit),
-                fSecurityManager.getStateLiteral(limit)},
+                    e, XMLErrorReporter.SEVERITY_FATAL_ERROR);
+        }
+        if (fSecurityManager.isOverLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
+            fSecurityManager.debugPrint(fLimitAnalyzer);
+            fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "TotalEntitySizeLimit",
+                    new Object[]{fLimitAnalyzer.getTotalValue(Limit.TOTAL_ENTITY_SIZE_LIMIT),
+                fSecurityManager.getLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT),
+                fSecurityManager.getStateLiteral(Limit.TOTAL_ENTITY_SIZE_LIMIT)},
                     XMLErrorReporter.SEVERITY_FATAL_ERROR);
         }
     }
@@ -942,7 +1016,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public int scanContent(XMLString content) throws IOException {
+    protected int scanContent(XMLString content) throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(scanContent: ");
             print();
@@ -963,6 +1037,7 @@
         int offset = fCurrentEntity.position;
         int c = fCurrentEntity.ch[offset];
         int newlines = 0;
+        boolean counted = false;
         if (c == '\n' || (c == '\r' && isExternal)) {
             if (DEBUG_BUFFER) {
                 System.out.print("[newline, "+offset+", "+fCurrentEntity.position+": ");
@@ -976,9 +1051,11 @@
                     fCurrentEntity.lineNumber++;
                     fCurrentEntity.columnNumber = 1;
                     if (fCurrentEntity.position == fCurrentEntity.count) {
+                        checkEntityLimit(null, fCurrentEntity, offset, newlines);
                         offset = 0;
                         fCurrentEntity.position = newlines;
                         if (load(newlines, false, true)) {
+                            counted = true;
                             break;
                         }
                     }
@@ -995,9 +1072,11 @@
                     fCurrentEntity.lineNumber++;
                     fCurrentEntity.columnNumber = 1;
                     if (fCurrentEntity.position == fCurrentEntity.count) {
+                        checkEntityLimit(null, fCurrentEntity, offset, newlines);
                         offset = 0;
                         fCurrentEntity.position = newlines;
                         if (load(newlines, false, true)) {
+                            counted = true;
                             break;
                         }
                     }
@@ -1011,6 +1090,7 @@
             }
             int length = fCurrentEntity.position - offset;
             if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+                checkEntityLimit(null, fCurrentEntity, offset, length);
                 //CHANGED: dont replace the value.. append to the buffer. This gives control to the callee
                 //on buffering the data..
                 content.setValues(fCurrentEntity.ch, offset, length);
@@ -1038,8 +1118,8 @@
         }
         int length = fCurrentEntity.position - offset;
         fCurrentEntity.columnNumber += length - newlines;
-        if (fCurrentEntity.isGE) {
-            checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length);
+        if (!counted) {
+            checkEntityLimit(null, fCurrentEntity, offset, length);
         }
 
         //CHANGED: dont replace the value.. append to the buffer. This gives control to the callee
@@ -1086,6 +1166,7 @@
      * @param quote   The quote character that signifies the end of the
      *                attribute value data.
      * @param content The content structure to fill.
+     * @param isNSURI a flag indicating whether the content is a Namespace URI
      *
      * @return Returns the next character on the input, if known. This
      *         value may be -1 but this does <em>note</em> designate
@@ -1094,7 +1175,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public int scanLiteral(int quote, XMLString content)
+    protected int scanLiteral(int quote, XMLString content, boolean isNSURI)
     throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(scanLiteral, '"+(char)quote+"': ");
@@ -1205,8 +1286,10 @@
         }
         int length = fCurrentEntity.position - offset;
         fCurrentEntity.columnNumber += length - newlines;
-        if (fCurrentEntity.isGE) {
-            checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length);
+
+        checkEntityLimit(null, fCurrentEntity, offset, length);
+        if (isNSURI) {
+            checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
         }
         content.setValues(fCurrentEntity.ch, offset, length);
 
@@ -1273,7 +1356,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public boolean scanData(String delimiter, XMLStringBuffer buffer)
+    protected boolean scanData(String delimiter, XMLStringBuffer buffer)
     throws IOException {
 
         boolean done = false;
@@ -1311,6 +1394,7 @@
             if (fCurrentEntity.position > fCurrentEntity.count - delimLen) {
                 // something must be wrong with the input:  e.g., file ends in an unterminated comment
                 int length = fCurrentEntity.count - fCurrentEntity.position;
+                checkEntityLimit(NameType.COMMENT, fCurrentEntity, fCurrentEntity.position, length);
                 buffer.append (fCurrentEntity.ch, fCurrentEntity.position, length);
                 fCurrentEntity.columnNumber += fCurrentEntity.count;
                 fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
@@ -1373,6 +1457,7 @@
                 }
                 int length = fCurrentEntity.position - offset;
                 if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+                    checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
                     buffer.append(fCurrentEntity.ch, offset, length);
                     if (DEBUG_BUFFER) {
                         System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": ");
@@ -1416,12 +1501,14 @@
                     fCurrentEntity.position--;
                     int length = fCurrentEntity.position - offset;
                     fCurrentEntity.columnNumber += length - newlines;
+                    checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
                     buffer.append(fCurrentEntity.ch, offset, length);
                     return true;
                 }
             }
             int length = fCurrentEntity.position - offset;
             fCurrentEntity.columnNumber += length - newlines;
+            checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
             if (done) {
                 length -= delimLen;
             }
@@ -1445,13 +1532,14 @@
      * the specified character.
      *
      * @param c The character to skip.
+     * @param nt The type of the name (element or attribute)
      *
      * @return Returns true if the character was skipped.
      *
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public boolean skipChar(int c) throws IOException {
+    protected boolean skipChar(int c, NameType nt) throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(skipChar, '"+(char)c+"': ");
             print();
@@ -1464,6 +1552,7 @@
         }
 
         // skip character
+        int offset = fCurrentEntity.position;
         int cc = fCurrentEntity.ch[fCurrentEntity.position];
         if (cc == c) {
             fCurrentEntity.position++;
@@ -1478,6 +1567,7 @@
                 print();
                 System.out.println(" -> true");
             }
+            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
             return true;
         } else if (c == '\n' && cc == '\r' && isExternal) {
             // handle newlines
@@ -1497,6 +1587,7 @@
                 print();
                 System.out.println(" -> true");
             }
+            checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
             return true;
         }
 
@@ -1526,7 +1617,7 @@
      *
      * @see com.sun.org.apache.xerces.internal.util.XMLChar#isSpace
      */
-    public boolean skipSpaces() throws IOException {
+    protected boolean skipSpaces() throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(skipSpaces: ");
             print();
@@ -1550,6 +1641,7 @@
 
         // skip spaces
         int c = fCurrentEntity.ch[fCurrentEntity.position];
+        int offset = fCurrentEntity.position - 1;
         if (XMLChar.isSpace(c)) {
             do {
                 boolean entityChanged = false;
@@ -1579,6 +1671,11 @@
                 } else {
                     fCurrentEntity.columnNumber++;
                 }
+
+                //If this is a general entity, spaces within a start element should be counted
+                checkEntityLimit(null, fCurrentEntity, offset, fCurrentEntity.position - offset);
+                offset = fCurrentEntity.position;
+
                 // load more characters, if needed
                 if (!entityChanged){
                     fCurrentEntity.position++;
@@ -1620,7 +1717,7 @@
 
 
     /**
-     * @param legnth This function checks that following number of characters are available.
+     * @param length This function checks that following number of characters are available.
      * to the underlying buffer.
      * @return This function returns true if capacity asked is available.
      */
@@ -1629,9 +1726,9 @@
     }
 
     /**
-     * @param legnth This function checks that following number of characters are available.
+     * @param length This function checks that following number of characters are available.
      * to the underlying buffer.
-     * @param if the underlying function should change the entity
+     * @param changeEntity a flag to indicate that the underlying function should change the entity
      * @return This function returns true if capacity asked is available.
      *
      */
@@ -1694,7 +1791,7 @@
      * @throws IOException  Thrown if i/o error occurs.
      * @throws EOFException Thrown on end of file.
      */
-    public boolean skipString(String s) throws IOException {
+    protected boolean skipString(String s) throws IOException {
 
         final int length = s.length();
 
@@ -1714,6 +1811,9 @@
                 if(afterSkip-- == beforeSkip){
                     fCurrentEntity.position = fCurrentEntity.position + length ;
                     fCurrentEntity.columnNumber += length;
+                    if (!detectingVersion) {
+                        checkEntityLimit(null, fCurrentEntity, beforeSkip, length);
+                    }
                     return true;
                 }
             }
@@ -1722,7 +1822,7 @@
         return false;
     } // skipString(String):boolean
 
-    public boolean skipString(char [] s) throws IOException {
+    protected boolean skipString(char [] s) throws IOException {
 
         final int length = s.length;
         //first make sure that required capacity is avaible
@@ -1741,6 +1841,9 @@
             }
             fCurrentEntity.position = fCurrentEntity.position + length ;
             fCurrentEntity.columnNumber += length;
+            if (!detectingVersion) {
+                checkEntityLimit(null, fCurrentEntity, beforeSkip, length);
+            }
             return true;
 
         }
@@ -2138,7 +2241,7 @@
      *
      * @see com.sun.org.apache.xerces.internal.util.XMLChar#isSpace
      */
-    public final boolean skipDeclSpaces() throws IOException {
+    protected final boolean skipDeclSpaces() throws IOException {
         if (DEBUG_BUFFER) {
             System.out.print("(skipDeclSpaces: ");
             //XMLEntityManager.print(fCurrentEntity);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -189,9 +189,9 @@
             // There are two variables,fNamespaces and fBindNamespaces
             //StAX uses XMLNSDocumentScannerImpl so this distinction needs to be maintained
             if (fNamespaces) {
-                fEntityScanner.scanQName(fElementQName);
+                fEntityScanner.scanQName(fElementQName, NameType.ELEMENTSTART);
             } else {
-                String name = fEntityScanner.scanName();
+                String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
                 fElementQName.setValues(null, name, name, null);
             }
 
@@ -404,11 +404,11 @@
         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
 
         // name
-        fEntityScanner.scanQName(fAttributeQName);
+        fEntityScanner.scanQName(fAttributeQName, NameType.ATTRIBUTE);
 
         // equals
         fEntityScanner.skipSpaces();
-        if (!fEntityScanner.skipChar('=')) {
+        if (!fEntityScanner.skipChar('=', NameType.ATTRIBUTE)) {
             reportFatalError("EqRequiredInAttribute",
                     new Object[]{fCurrentElement.rawname,fAttributeQName.rawname});
         }
@@ -430,23 +430,28 @@
         //since scanAttributeValue doesn't use attIndex parameter therefore we
         //can safely add the attribute later..
         XMLString tmpStr = getString();
-        scanAttributeValue(tmpStr, fTempString2,
-                fAttributeQName.rawname, attributes,
-                attrIndex, isVC, fCurrentElement.rawname);
+
+        /**
+         * Determine whether this is a namespace declaration that will be subject
+         * to the name limit check in the scanAttributeValue operation.
+         * Namespace declaration format: xmlns="..." or xmlns:prefix="..."
+         * Note that prefix:xmlns="..." isn't a namespace.
+         */
+        String localpart = fAttributeQName.localpart;
+        String prefix = fAttributeQName.prefix != null
+                ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
+        boolean isNSDecl = fBindNamespaces & (prefix == XMLSymbols.PREFIX_XMLNS ||
+                    prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS);
+
+        scanAttributeValue(tmpStr, fTempString2, fAttributeQName.rawname, attributes,
+                attrIndex, isVC, fCurrentElement.rawname, isNSDecl);
 
         String value = null;
         //fTempString.toString();
 
         // record namespace declarations if any.
         if (fBindNamespaces) {
-
-            String localpart = fAttributeQName.localpart;
-            String prefix = fAttributeQName.prefix != null
-                    ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
-            // when it's of form xmlns="..." or xmlns:prefix="...",
-            // it's a namespace declaration. but prefix:xmlns="..." isn't.
-            if (prefix == XMLSymbols.PREFIX_XMLNS ||
-                    prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) {
+            if (isNSDecl) {
                 //check the length of URI
                 if (tmpStr.length > fXMLNameLimit) {
                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java	Wed Jul 05 22:00:06 2017 +0200
@@ -114,6 +114,30 @@
     /** Debug attribute normalization. */
     protected static final boolean DEBUG_ATTR_NORMALIZATION = false;
 
+    /**
+     * Type of names
+     */
+    public static enum NameType {
+        ATTRIBUTE("attribute"),
+        ATTRIBUTENAME("attribute name"),
+        COMMENT("comment"),
+        DOCTYPE("doctype"),
+        ELEMENTSTART("startelement"),
+        ELEMENTEND("endelement"),
+        ENTITY("entity"),
+        NOTATION("notation"),
+        PI("pi"),
+        REFERENCE("reference");
+
+        final String literal;
+        NameType(String literal) {
+            this.literal = literal;
+        }
+
+        String literal() {
+            return literal;
+        }
+    }
 
     //xxx: setting the default value as false, as we dont need to calculate this value
     //we should have a feature when set to true computes this value
@@ -144,7 +168,7 @@
     protected boolean fNotifyCharRefs = false;
 
     /** Internal parser-settings feature */
-        protected boolean fParserSettings = true;
+    protected boolean fParserSettings = true;
 
     // properties
 
@@ -173,13 +197,13 @@
     /** event type */
     protected XMLEvent fEvent ;
 
-    /** Entity scanner, this alwasy works on last entity that was opened. */
+    /** Entity scanner, this always works on last entity that was opened. */
     protected XMLEntityScanner fEntityScanner = null;
 
     /** Entity depth. */
     protected int fEntityDepth;
 
-    /** Literal value of the last character refence scanned. */
+    /** Literal value of the last character reference scanned. */
     protected String fCharRefLiteral = null;
 
     /** Scanning attribute. */
@@ -547,10 +571,10 @@
         }
 
         // end
-        if (!fEntityScanner.skipChar('?')) {
+        if (!fEntityScanner.skipChar('?', null)) {
             reportFatalError("XMLDeclUnterminated", null);
         }
-        if (!fEntityScanner.skipChar('>')) {
+        if (!fEntityScanner.skipChar('>', null)) {
             reportFatalError("XMLDeclUnterminated", null);
 
         }
@@ -577,7 +601,7 @@
      * <strong>Note:</strong> This method uses fStringBuffer2, anything in it
      * at the time of calling is lost.
      */
-    public String scanPseudoAttribute(boolean scanningTextDecl,
+    protected String scanPseudoAttribute(boolean scanningTextDecl,
             XMLString value)
             throws IOException, XNIException {
 
@@ -588,7 +612,7 @@
             reportFatalError("PseudoAttrNameExpected", null);
         }
         fEntityScanner.skipSpaces();
-        if (!fEntityScanner.skipChar('=')) {
+        if (!fEntityScanner.skipChar('=', null)) {
             reportFatalError(scanningTextDecl ? "EqRequiredInTextDecl"
                     : "EqRequiredInXMLDecl", new Object[]{name});
         }
@@ -598,15 +622,15 @@
             reportFatalError(scanningTextDecl ? "QuoteRequiredInTextDecl"
                     : "QuoteRequiredInXMLDecl" , new Object[]{name});
         }
-        fEntityScanner.scanChar();
-        int c = fEntityScanner.scanLiteral(quote, value);
+        fEntityScanner.scanChar(NameType.ATTRIBUTE);
+        int c = fEntityScanner.scanLiteral(quote, value, false);
         if (c != quote) {
             fStringBuffer2.clear();
             do {
                 fStringBuffer2.append(value);
                 if (c != -1) {
                     if (c == '&' || c == '%' || c == '<' || c == ']') {
-                        fStringBuffer2.append((char)fEntityScanner.scanChar());
+                        fStringBuffer2.append((char)fEntityScanner.scanChar(NameType.ATTRIBUTE));
                     } else if (XMLChar.isHighSurrogate(c)) {
                         scanSurrogates(fStringBuffer2);
                     } else if (isInvalidLiteral(c)) {
@@ -614,15 +638,15 @@
                                 ? "InvalidCharInTextDecl" : "InvalidCharInXMLDecl";
                         reportFatalError(key,
                                 new Object[] {Integer.toString(c, 16)});
-                                fEntityScanner.scanChar();
+                                fEntityScanner.scanChar(null);
                     }
                 }
-                c = fEntityScanner.scanLiteral(quote, value);
+                c = fEntityScanner.scanLiteral(quote, value, false);
             } while (c != quote);
             fStringBuffer2.append(value);
             value.setValues(fStringBuffer2);
         }
-        if (!fEntityScanner.skipChar(quote)) {
+        if (!fEntityScanner.skipChar(quote, null)) {
             reportFatalError(scanningTextDecl ? "CloseQuoteMissingInTextDecl"
                     : "CloseQuoteMissingInXMLDecl",
                     new Object[]{name});
@@ -680,7 +704,7 @@
 
         // target
         fReportEntity = false;
-        String target = fEntityScanner.scanName();
+        String target = fEntityScanner.scanName(NameType.PI);
         if (target == null) {
             reportFatalError("PITargetRequired", null);
         }
@@ -745,7 +769,7 @@
                     } else if (isInvalidLiteral(c)) {
                         reportFatalError("InvalidCharInPI",
                                 new Object[]{Integer.toHexString(c)});
-                                fEntityScanner.scanChar();
+                                fEntityScanner.scanChar(null);
                     }
                 }
             } while (fEntityScanner.scanData("?>", data));
@@ -786,11 +810,11 @@
                 else if (isInvalidLiteral(c)) {
                     reportFatalError("InvalidCharInComment",
                             new Object[] { Integer.toHexString(c) });
-                            fEntityScanner.scanChar();
+                            fEntityScanner.scanChar(NameType.COMMENT);
                 }
             }
         }
-        if (!fEntityScanner.skipChar('>')) {
+        if (!fEntityScanner.skipChar('>', NameType.COMMENT)) {
             reportFatalError("DashDashInComment", null);
         }
 
@@ -811,15 +835,14 @@
      * @param checkEntities true if undeclared entities should be reported as VC violation,
      *                      false if undeclared entities should be reported as WFC violation.
      * @param eleName The name of element to which this attribute belongs.
+     * @param isNSURI a flag indicating whether the content is a Namespace URI
      *
      * <strong>Note:</strong> This method uses fStringBuffer2, anything in it
      * at the time of calling is lost.
      **/
-    protected void scanAttributeValue(XMLString value,
-            XMLString nonNormalizedValue,
-            String atName,
-            XMLAttributes attributes, int attrIndex,
-            boolean checkEntities, String eleName)
+    protected void scanAttributeValue(XMLString value, XMLString nonNormalizedValue,
+            String atName, XMLAttributes attributes, int attrIndex, boolean checkEntities,
+            String eleName, boolean isNSURI)
             throws IOException, XNIException {
         XMLStringBuffer stringBuffer = null;
         // quote
@@ -828,10 +851,10 @@
             reportFatalError("OpenQuoteExpected", new Object[]{eleName, atName});
         }
 
-        fEntityScanner.scanChar();
+        fEntityScanner.scanChar(NameType.ATTRIBUTE);
         int entityDepth = fEntityDepth;
 
-        int c = fEntityScanner.scanLiteral(quote, value);
+        int c = fEntityScanner.scanLiteral(quote, value, isNSURI);
         if (DEBUG_ATTR_NORMALIZATION) {
             System.out.println("** scanLiteral -> \""
                     + value.toString() + "\"");
@@ -857,11 +880,11 @@
                             + stringBuffer.toString() + "\"");
                 }
                 if (c == '&') {
-                    fEntityScanner.skipChar('&');
+                    fEntityScanner.skipChar('&', NameType.REFERENCE);
                     if (entityDepth == fEntityDepth && fNeedNonNormalizedValue ) {
                         fStringBuffer2.append('&');
                     }
-                    if (fEntityScanner.skipChar('#')) {
+                    if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
                         if (entityDepth == fEntityDepth && fNeedNonNormalizedValue ) {
                             fStringBuffer2.append('#');
                         }
@@ -879,53 +902,20 @@
                             }
                         }
                     } else {
-                        String entityName = fEntityScanner.scanName();
+                        String entityName = fEntityScanner.scanName(NameType.ENTITY);
                         if (entityName == null) {
                             reportFatalError("NameRequiredInReference", null);
                         } else if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
                             fStringBuffer2.append(entityName);
                         }
-                        if (!fEntityScanner.skipChar(';')) {
+                        if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
                             reportFatalError("SemicolonRequiredInReference",
                                     new Object []{entityName});
                         } else if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
                             fStringBuffer2.append(';');
                         }
-                        if (entityName == fAmpSymbol) {
-                            stringBuffer.append('&');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** value5: \""
-                                        + stringBuffer.toString()
-                                        + "\"");
-                            }
-                        } else if (entityName == fAposSymbol) {
-                            stringBuffer.append('\'');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** value7: \""
-                                        + stringBuffer.toString()
-                                        + "\"");
-                            }
-                        } else if (entityName == fLtSymbol) {
-                            stringBuffer.append('<');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** value9: \""
-                                        + stringBuffer.toString()
-                                        + "\"");
-                            }
-                        } else if (entityName == fGtSymbol) {
-                            stringBuffer.append('>');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** valueB: \""
-                                        + stringBuffer.toString()
-                                        + "\"");
-                            }
-                        } else if (entityName == fQuotSymbol) {
-                            stringBuffer.append('"');
-                            if (DEBUG_ATTR_NORMALIZATION) {
-                                System.out.println("** valueD: \""
-                                        + stringBuffer.toString()
-                                        + "\"");
-                            }
+                        if (resolveCharacter(entityName, stringBuffer)) {
+                            checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
                         } else {
                             if (fEntityStore.isExternalEntity(entityName)) {
                                 reportFatalError("ReferenceToExternalEntity",
@@ -952,12 +942,12 @@
                 } else if (c == '<') {
                     reportFatalError("LessthanInAttValue",
                             new Object[] { eleName, atName });
-                            fEntityScanner.scanChar();
+                            fEntityScanner.scanChar(null);
                             if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
                                 fStringBuffer2.append((char)c);
                             }
                 } else if (c == '%' || c == ']') {
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     stringBuffer.append((char)c);
                     if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
                         fStringBuffer2.append((char)c);
@@ -967,7 +957,7 @@
                                 + stringBuffer.toString() + "\"");
                     }
                 } else if (c == '\n' || c == '\r') {
-                    fEntityScanner.scanChar();
+                    fEntityScanner.scanChar(null);
                     stringBuffer.append(' ');
                     if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
                         fStringBuffer2.append('\n');
@@ -988,12 +978,12 @@
                 } else if (c != -1 && isInvalidLiteral(c)) {
                     reportFatalError("InvalidCharInAttValue",
                             new Object[] {eleName, atName, Integer.toString(c, 16)});
-                            fEntityScanner.scanChar();
+                            fEntityScanner.scanChar(null);
                             if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
                                 fStringBuffer2.append((char)c);
                             }
                 }
-                c = fEntityScanner.scanLiteral(quote, value);
+                c = fEntityScanner.scanLiteral(quote, value, isNSURI);
                 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
                     fStringBuffer2.append(value);
                 }
@@ -1014,7 +1004,7 @@
             nonNormalizedValue.setValues(fStringBuffer2);
 
         // quote
-        int cquote = fEntityScanner.scanChar();
+        int cquote = fEntityScanner.scanChar(NameType.ATTRIBUTE);
         if (cquote != quote) {
             reportFatalError("CloseQuoteExpected", new Object[]{eleName, atName});
         }
@@ -1022,6 +1012,39 @@
 
 
     /**
+     * Resolves character entity references.
+     * @param entityName the name of the entity
+     * @param stringBuffer the current XMLStringBuffer to append the character to.
+     * @return true if resolved, false otherwise
+     */
+    protected boolean resolveCharacter(String entityName, XMLStringBuffer stringBuffer) {
+        /**
+         * entityNames (symbols) are interned. The equals method would do the same,
+         * but I'm leaving it as comparisons by references are common in the impl
+         * and it made it explicit to others who read this code.
+         */
+        if (entityName == fAmpSymbol) {
+            stringBuffer.append('&');
+            return true;
+        } else if (entityName == fAposSymbol) {
+            stringBuffer.append('\'');
+            return true;
+        } else if (entityName == fLtSymbol) {
+            stringBuffer.append('<');
+            return true;
+        } else if (entityName == fGtSymbol) {
+            checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
+            stringBuffer.append('>');
+            return true;
+        } else if (entityName == fQuotSymbol) {
+            checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
+            stringBuffer.append('"');
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Scans External ID and return the public and system IDs.
      *
      * @param identifiers An array of size 2 to return the system id,
@@ -1064,25 +1087,25 @@
                 }
                 reportFatalError("QuoteRequiredInSystemID", null);
             }
-            fEntityScanner.scanChar();
+            fEntityScanner.scanChar(null);
             XMLString ident = fString;
-            if (fEntityScanner.scanLiteral(quote, ident) != quote) {
+            if (fEntityScanner.scanLiteral(quote, ident, false) != quote) {
                 fStringBuffer.clear();
                 do {
                     fStringBuffer.append(ident);
                     int c = fEntityScanner.peekChar();
                     if (XMLChar.isMarkup(c) || c == ']') {
-                        fStringBuffer.append((char)fEntityScanner.scanChar());
+                        fStringBuffer.append((char)fEntityScanner.scanChar(null));
                     } else if (c != -1 && isInvalidLiteral(c)) {
                         reportFatalError("InvalidCharInSystemID",
                             new Object[] {Integer.toString(c, 16)});
                     }
-                } while (fEntityScanner.scanLiteral(quote, ident) != quote);
+                } while (fEntityScanner.scanLiteral(quote, ident, false) != quote);
                 fStringBuffer.append(ident);
                 ident = fStringBuffer;
             }
             systemId = ident.toString();
-            if (!fEntityScanner.skipChar(quote)) {
+            if (!fEntityScanner.skipChar(quote, null)) {
                 reportFatalError("SystemIDUnterminated", null);
             }
         }
@@ -1114,7 +1137,7 @@
      */
     protected boolean scanPubidLiteral(XMLString literal)
     throws IOException, XNIException {
-        int quote = fEntityScanner.scanChar();
+        int quote = fEntityScanner.scanChar(null);
         if (quote != '\'' && quote != '"') {
             reportFatalError("QuoteRequiredInPublicID", null);
             return false;
@@ -1125,7 +1148,7 @@
         boolean skipSpace = true;
         boolean dataok = true;
         while (true) {
-            int c = fEntityScanner.scanChar();
+            int c = fEntityScanner.scanChar(null);
             if (c == ' ' || c == '\n' || c == '\r') {
                 if (!skipSpace) {
                     // take the first whitespace as a space and skip the others
@@ -1241,9 +1264,10 @@
      */
     protected int scanCharReferenceValue(XMLStringBuffer buf, XMLStringBuffer buf2)
     throws IOException, XNIException {
+        int initLen = buf.length;
         // scan hexadecimal value
         boolean hex = false;
-        if (fEntityScanner.skipChar('x')) {
+        if (fEntityScanner.skipChar('x', NameType.REFERENCE)) {
             if (buf2 != null) { buf2.append('x'); }
             hex = true;
             fStringBuffer3.clear();
@@ -1255,7 +1279,7 @@
                     (c >= 'A' && c <= 'F');
             if (digit) {
                 if (buf2 != null) { buf2.append((char)c); }
-                fEntityScanner.scanChar();
+                fEntityScanner.scanChar(NameType.REFERENCE);
                 fStringBuffer3.append((char)c);
 
                 do {
@@ -1265,7 +1289,7 @@
                             (c >= 'A' && c <= 'F');
                     if (digit) {
                         if (buf2 != null) { buf2.append((char)c); }
-                        fEntityScanner.scanChar();
+                        fEntityScanner.scanChar(NameType.REFERENCE);
                         fStringBuffer3.append((char)c);
                     }
                 } while (digit);
@@ -1283,7 +1307,7 @@
             digit = c >= '0' && c <= '9';
             if (digit) {
                 if (buf2 != null) { buf2.append((char)c); }
-                fEntityScanner.scanChar();
+                fEntityScanner.scanChar(NameType.REFERENCE);
                 fStringBuffer3.append((char)c);
 
                 do {
@@ -1291,7 +1315,7 @@
                     digit = c >= '0' && c <= '9';
                     if (digit) {
                         if (buf2 != null) { buf2.append((char)c); }
-                        fEntityScanner.scanChar();
+                        fEntityScanner.scanChar(NameType.REFERENCE);
                         fStringBuffer3.append((char)c);
                     }
                 } while (digit);
@@ -1301,7 +1325,7 @@
         }
 
         // end
-        if (!fEntityScanner.skipChar(';')) {
+        if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
             reportFatalError("SemicolonRequiredInCharRef", null);
         }
         if (buf2 != null) { buf2.append(';'); }
@@ -1347,6 +1371,9 @@
             }
         }
 
+        if (fEntityScanner.fCurrentEntity.isGE) {
+            checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, buf.length - initLen);
+        }
         return value;
     }
     // returns true if the given character is not
@@ -1408,14 +1435,14 @@
     protected boolean scanSurrogates(XMLStringBuffer buf)
     throws IOException, XNIException {
 
-        int high = fEntityScanner.scanChar();
+        int high = fEntityScanner.scanChar(null);
         int low = fEntityScanner.peekChar();
         if (!XMLChar.isLowSurrogate(low)) {
             reportFatalError("InvalidCharInContent",
                     new Object[] {Integer.toString(high, 16)});
                     return false;
         }
-        fEntityScanner.scanChar();
+        fEntityScanner.scanChar(null);
 
         // convert surrogates to supplemental character
         int c = XMLChar.supplemental((char)high, (char)low);
@@ -1478,5 +1505,52 @@
         }
     }
 
+    /**
+     * Add the count of the content buffer and check if the accumulated
+     * value exceeds the limit
+     * @param isPEDecl a flag to indicate whether the entity is parameter
+     * @param entityName entity name
+     * @param buffer content buffer
+     */
+    void checkEntityLimit(boolean isPEDecl, String entityName, XMLString buffer) {
+        checkEntityLimit(isPEDecl, entityName, buffer.length);
+    }
 
+    /**
+     * Add the count and check limit
+     * @param isPEDecl a flag to indicate whether the entity is parameter
+     * @param entityName entity name
+     * @param len length of the buffer
+     */
+    void checkEntityLimit(boolean isPEDecl, String entityName, int len) {
+        if (fLimitAnalyzer == null) {
+            fLimitAnalyzer = fEntityManager.fLimitAnalyzer;
+        }
+        if (isPEDecl) {
+            fLimitAnalyzer.addValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, "%" + entityName, len);
+            if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
+                        fSecurityManager.debugPrint(fLimitAnalyzer);
+                reportFatalError("MaxEntitySizeLimit", new Object[]{"%" + entityName,
+                    fLimitAnalyzer.getValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
+                    fSecurityManager.getLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
+                    fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT)});
+            }
+        } else {
+            fLimitAnalyzer.addValue(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName, len);
+            if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
+                        fSecurityManager.debugPrint(fLimitAnalyzer);
+                reportFatalError("MaxEntitySizeLimit", new Object[]{entityName,
+                    fLimitAnalyzer.getValue(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT),
+                    fSecurityManager.getLimit(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT),
+                    fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT)});
+            }
+        }
+        if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
+            fSecurityManager.debugPrint(fLimitAnalyzer);
+            reportFatalError("TotalEntitySizeLimit",
+                new Object[]{fLimitAnalyzer.getTotalValue(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
+                fSecurityManager.getLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
+                fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT)});
+        }
+    }
 } // class XMLScanner
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLVersionDetector.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLVersionDetector.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,62 +1,21 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999-2003 The Apache Software Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- *    if any, must include the following acknowledgment:
- *       "This product includes software developed by the
- *        Apache Software Foundation (http://www.apache.org/)."
- *    Alternately, this acknowledgment may appear in the software itself,
- *    if and wherever such third-party acknowledgments normally appear.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * 4. The names "Xerces" and "Apache Software Foundation" must
- *    not be used to endorse or promote products derived from this
- *    software without prior written permission. For written
- *    permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- *    nor may "Apache" appear in their name, without prior written
- *    permission of the Apache Software Foundation.
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 2003, International
- * Business Machines, Inc., http://www.apache.org.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package com.sun.org.apache.xerces.internal.impl;
@@ -192,40 +151,46 @@
         // in the XML declaration.
         fEntityManager.setScannerVersion(Constants.XML_VERSION_1_0);
         XMLEntityScanner scanner = fEntityManager.getEntityScanner();
+        scanner.detectingVersion = true;
         try {
             if (!scanner.skipString("<?xml")) {
                 // definitely not a well-formed 1.1 doc!
+                scanner.detectingVersion = false;
                 return Constants.XML_VERSION_1_0;
             }
             if (!scanner.skipDeclSpaces()) {
                 fixupCurrentEntity(fEntityManager, fExpectedVersionString, 5);
+                scanner.detectingVersion = false;
                 return Constants.XML_VERSION_1_0;
             }
             if (!scanner.skipString("version")) {
                 fixupCurrentEntity(fEntityManager, fExpectedVersionString, 6);
+                scanner.detectingVersion = false;
                 return Constants.XML_VERSION_1_0;
             }
             scanner.skipDeclSpaces();
             // Check if the next character is '='. If it is then consume it.
             if (scanner.peekChar() != '=') {
                 fixupCurrentEntity(fEntityManager, fExpectedVersionString, 13);
+                scanner.detectingVersion = false;
                 return Constants.XML_VERSION_1_0;
             }
-            scanner.scanChar();
+            scanner.scanChar(null);
             scanner.skipDeclSpaces();
-            int quoteChar = scanner.scanChar();
+            int quoteChar = scanner.scanChar(null);
             fExpectedVersionString[14] = (char) quoteChar;
             for (int versionPos = 0; versionPos < XML11_VERSION.length; versionPos++) {
-                fExpectedVersionString[15 + versionPos] = (char) scanner.scanChar();
+                fExpectedVersionString[15 + versionPos] = (char) scanner.scanChar(null);
             }
             // REVISIT:  should we check whether this equals quoteChar?
-            fExpectedVersionString[18] = (char) scanner.scanChar();
+            fExpectedVersionString[18] = (char) scanner.scanChar(null);
             fixupCurrentEntity(fEntityManager, fExpectedVersionString, 19);
             int matched = 0;
             for (; matched < XML11_VERSION.length; matched++) {
                 if (fExpectedVersionString[15 + matched] != XML11_VERSION[matched])
                     break;
             }
+            scanner.detectingVersion = false;
             if (matched == XML11_VERSION.length)
                 return Constants.XML_VERSION_1_1;
             return Constants.XML_VERSION_1_0;
@@ -237,10 +202,9 @@
                 "PrematureEOF",
                 null,
                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
+            scanner.detectingVersion = false;
             return Constants.XML_VERSION_1_0;
-
         }
-
     }
 
     // This method prepends "length" chars from the char array,
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties	Wed Jul 05 22:00:06 2017 +0200
@@ -298,7 +298,8 @@
         EntityExpansionLimit=JAXP00010001: The parser has encountered more than \"{0}\" entity expansions in this document; this is the limit imposed by the JDK.
         ElementAttributeLimit=JAXP00010002:  Element \"{0}\" has more than \"{1}\" attributes, \"{1}\" is the limit imposed by the JDK.
         MaxEntitySizeLimit=JAXP00010003: The length of entity \"{0}\" is \"{1}\" that exceeds the \"{2}\" limit set by \"{3}\".
-        TotalEntitySizeLimit=JAXP00010004: The accumulated size of entities is \"{1}\" that exceeded the \"{2}\" limit set by \"{3}\".
+        TotalEntitySizeLimit=JAXP00010004: The accumulated size of entities is \"{0}\" that exceeded the \"{1}\" limit set by \"{2}\".
         MaxXMLNameLimit=JAXP00010005: The length of entity \"{0}\" is \"{1}\" that exceeds the \"{2}\" limit set by \"{3}\".
         MaxElementDepthLimit=JAXP00010006: The element \"{0}\" has a depth of \"{1}\" that exceeds the limit \"{2}\" set by \"{3}\".
+        EntityReplacementLimit=JAXP00010007: The total number of nodes in entity references is \"{0}\" that is over the limit \"{1}\" set by \"{2}\".
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/XMLLimitAnalyzer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/XMLLimitAnalyzer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -129,13 +129,15 @@
         if (index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() ||
                 index == Limit.MAX_OCCUR_NODE_LIMIT.ordinal() ||
                 index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() ||
-                index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal()
+                index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() ||
+                index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal()
                 ) {
             totalValue[index] += value;
             return;
         }
         if (index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() ||
                 index == Limit.MAX_NAME_LIMIT.ordinal()) {
+            values[index] = value;
             totalValue[index] = value;
             return;
         }
@@ -175,10 +177,13 @@
      * @return the value of the property
      */
     public int getValue(Limit limit) {
-        return values[limit.ordinal()];
+        return getValue(limit.ordinal());
     }
 
     public int getValue(int index) {
+        if (index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal()) {
+            return totalValue[index];
+        }
         return values[index];
     }
     /**
@@ -233,6 +238,11 @@
     public void reset(Limit limit) {
         if (limit.ordinal() == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal()) {
             totalValue[limit.ordinal()] = 0;
+        } else if (limit.ordinal() == Limit.GENERAL_ENTITY_SIZE_LIMIT.ordinal()) {
+            names[limit.ordinal()] = null;
+            values[limit.ordinal()] = 0;
+            caches[limit.ordinal()] = null;
+            totalValue[limit.ordinal()] = 0;
         }
     }
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/XMLSecurityManager.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/XMLSecurityManager.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -78,7 +78,9 @@
         MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit",
                 Constants.JDK_MAX_ELEMENT_DEPTH, Constants.SP_MAX_ELEMENT_DEPTH, 0, 0),
         MAX_NAME_LIMIT("MaxXMLNameLimit",
-                Constants.JDK_XML_NAME_LIMIT, Constants.SP_XML_NAME_LIMIT, 1000, 1000);
+                Constants.JDK_XML_NAME_LIMIT, Constants.SP_XML_NAME_LIMIT, 1000, 1000),
+        ENTITY_REPLACEMENT_LIMIT("EntityReplacementLimit",
+                Constants.JDK_ENTITY_REPLACEMENT_LIMIT, Constants.SP_ENTITY_REPLACEMENT_LIMIT, 0, 3000000);
 
         final String key;
         final String apiProperty;
@@ -450,6 +452,7 @@
         if (index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() ||
                 index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() ||
                 index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() ||
+                index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal() ||
                 index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() ||
                 index == Limit.MAX_NAME_LIMIT.ordinal()
                 ) {
--- a/jaxp/test/javax/xml/jaxp/unittest/transform/XSLTFunctionsTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxp/test/javax/xml/jaxp/unittest/transform/XSLTFunctionsTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,7 @@
 public class XSLTFunctionsTest {
 
     /**
-     * @bug 8062518
+     * @bug 8062518 8153082
      * Verifies that a reference to the DTM created by XSLT document function is
      * actually read from the DTM by an extension function.
      * @param xml Content of xml file to process
--- a/jaxws/.hgtags	Wed Jul 05 21:58:30 2017 +0200
+++ b/jaxws/.hgtags	Wed Jul 05 22:00:06 2017 +0200
@@ -373,3 +373,4 @@
 5b0570e3db29f6b8c80a4beac70d51284507b203 jdk-9+125
 264a44128cd6286e598d5a849ceeb613c06269d0 jdk-9+126
 06d706c70634775418dc79a2671780ba1c624fd2 jdk-9+127
+fe4e11bd2423635dc0f5f5cb9a64eb2f2cce7f4c jdk-9+128
--- a/jdk/.hgtags	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/.hgtags	Wed Jul 05 22:00:06 2017 +0200
@@ -370,3 +370,4 @@
 073ab1d4edf5590cf1af7b6d819350c14e425c1a jdk-9+125
 6fda66a5bdf2da8994032b9da2078a4137f4d954 jdk-9+126
 7a97b89ba83077ca62e4aa5a05437adc8f315343 jdk-9+127
+9446c534f0222b4eecfd9d9e25ab37c4fd4400a5 jdk-9+128
--- a/jdk/src/java.base/macosx/classes/java/lang/ClassLoaderHelper.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/macosx/classes/java/lang/ClassLoaderHelper.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.lang;
 
 import java.io.File;
--- a/jdk/src/java.base/macosx/native/libjava/java_props_macosx.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/macosx/native/libjava/java_props_macosx.c	Wed Jul 05 22:00:06 2017 +0200
@@ -177,8 +177,14 @@
         OSVerStruct (*procInfoFn)(id rec, SEL sel) = (OSVerStruct(*)(id, SEL))objc_msgSend_stret;
         OSVerStruct osVer = procInfoFn([NSProcessInfo processInfo],
                                        @selector(operatingSystemVersion));
-        NSString *nsVerStr = [NSString stringWithFormat:@"%ld.%ld.%ld",
-                (long)osVer.majorVersion, (long)osVer.minorVersion, (long)osVer.patchVersion];
+        NSString *nsVerStr;
+        if (osVer.patchVersion == 0) { // Omit trailing ".0"
+            nsVerStr = [NSString stringWithFormat:@"%ld.%ld",
+                    (long)osVer.majorVersion, (long)osVer.minorVersion];
+        } else {
+            nsVerStr = [NSString stringWithFormat:@"%ld.%ld.%ld",
+                    (long)osVer.majorVersion, (long)osVer.minorVersion, (long)osVer.patchVersion];
+        }
         // Copy out the char*
         osVersionCStr = strdup([nsVerStr UTF8String]);
     }
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -172,6 +172,11 @@
      */
     private final int fixedKeySize; // in bytes, -1 if no restriction
 
+    /*
+     * needed to enforce ISE thrown when updateAAD is called after update for GCM mode.
+     */
+    private boolean updateCalled;
+
     /**
      * Creates an instance of AES cipher with default ECB mode and
      * PKCS5Padding.
@@ -304,6 +309,7 @@
     protected void engineInit(int opmode, Key key, SecureRandom random)
         throws InvalidKeyException {
         checkKeySize(key, fixedKeySize);
+        updateCalled = false;
         core.init(opmode, key, random);
     }
 
@@ -336,6 +342,7 @@
                               SecureRandom random)
         throws InvalidKeyException, InvalidAlgorithmParameterException {
         checkKeySize(key, fixedKeySize);
+        updateCalled = false;
         core.init(opmode, key, params, random);
     }
 
@@ -344,6 +351,7 @@
                               SecureRandom random)
         throws InvalidKeyException, InvalidAlgorithmParameterException {
         checkKeySize(key, fixedKeySize);
+        updateCalled = false;
         core.init(opmode, key, params, random);
     }
 
@@ -368,6 +376,7 @@
      */
     protected byte[] engineUpdate(byte[] input, int inputOffset,
                                   int inputLen) {
+        updateCalled = true;
         return core.update(input, inputOffset, inputLen);
     }
 
@@ -397,6 +406,7 @@
     protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
                                byte[] output, int outputOffset)
         throws ShortBufferException {
+        updateCalled = true;
         return core.update(input, inputOffset, inputLen, output,
                            outputOffset);
     }
@@ -433,7 +443,9 @@
      */
     protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
         throws IllegalBlockSizeException, BadPaddingException {
-        return core.doFinal(input, inputOffset, inputLen);
+        byte[] out = core.doFinal(input, inputOffset, inputLen);
+        updateCalled = false;
+        return out;
     }
 
     /**
@@ -476,8 +488,10 @@
                                 byte[] output, int outputOffset)
         throws IllegalBlockSizeException, ShortBufferException,
                BadPaddingException {
-        return core.doFinal(input, inputOffset, inputLen, output,
-                            outputOffset);
+        int outLen = core.doFinal(input, inputOffset, inputLen, output,
+                                  outputOffset);
+        updateCalled = false;
+        return outLen;
     }
 
     /**
@@ -574,6 +588,9 @@
      */
     @Override
     protected void engineUpdateAAD(byte[] src, int offset, int len) {
+        if (core.getMode() == CipherCore.GCM_MODE && updateCalled) {
+            throw new IllegalStateException("AAD must be supplied before encryption/decryption starts");
+        }
         core.updateAAD(src, offset, len);
     }
 
@@ -606,6 +623,9 @@
      */
     @Override
     protected void engineUpdateAAD(ByteBuffer src) {
+        if (core.getMode() == CipherCore.GCM_MODE && updateCalled) {
+            throw new IllegalStateException("AAD must be supplied before encryption/decryption starts");
+        }
         if (src != null) {
             int aadLen = src.limit() - src.position();
             if (aadLen != 0) {
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -124,7 +124,7 @@
     private static final int PCBC_MODE = 4;
     private static final int CTR_MODE = 5;
     private static final int CTS_MODE = 6;
-    private static final int GCM_MODE = 7;
+    static final int GCM_MODE = 7;
 
     /*
      * variables used for performing the GCM (key+iv) uniqueness check.
@@ -196,7 +196,7 @@
             cipher = new CounterMode(rawImpl);
             unitBytes = 1;
             padding = null;
-        }  else if (modeUpperCase.startsWith("GCM")) {
+        }  else if (modeUpperCase.equals("GCM")) {
             // can only be used for block ciphers w/ 128-bit block size
             if (blockSize != 16) {
                 throw new NoSuchAlgorithmException
@@ -223,6 +223,15 @@
         }
     }
 
+    /**
+     * Returns the mode of this cipher.
+     *
+     * @return the parsed cipher mode
+     */
+    int getMode() {
+        return cipherMode;
+    }
+
     private static int getNumOfUnit(String mode, int offset, int blockSize)
         throws NoSuchAlgorithmException {
         int result = blockSize; // use blockSize as default value
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,6 +49,16 @@
     static int DEFAULT_TAG_LEN = AES_BLOCK_SIZE;
     static int DEFAULT_IV_LEN = 12; // in bytes
 
+    // In NIST SP 800-38D, GCM input size is limited to be no longer
+    // than (2^36 - 32) bytes. Otherwise, the counter will wrap
+    // around and lead to a leak of plaintext.
+    // However, given the current GCM spec requirement that recovered
+    // text can only be returned after successful tag verification,
+    // we are bound by limiting the data size to the size limit of
+    // java byte array, e.g. Integer.MAX_VALUE, since all data
+    // can only be returned by the doFinal(...) call.
+    private static final int MAX_BUF_SIZE = Integer.MAX_VALUE;
+
     // buffer for AAD data; if null, meaning update has been called
     private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
     private int sizeOfAAD = 0;
@@ -89,9 +99,13 @@
         }
     }
 
-    // ivLen in bits
-    private static byte[] getLengthBlock(int ivLen) {
+    private static byte[] getLengthBlock(int ivLenInBytes) {
+        long ivLen = ((long)ivLenInBytes) << 3;
         byte[] out = new byte[AES_BLOCK_SIZE];
+        out[8] = (byte)(ivLen >>> 56);
+        out[9] = (byte)(ivLen >>> 48);
+        out[10] = (byte)(ivLen >>> 40);
+        out[11] = (byte)(ivLen >>> 32);
         out[12] = (byte)(ivLen >>> 24);
         out[13] = (byte)(ivLen >>> 16);
         out[14] = (byte)(ivLen >>> 8);
@@ -99,13 +113,22 @@
         return out;
     }
 
-    // aLen and cLen both in bits
-    private static byte[] getLengthBlock(int aLen, int cLen) {
+    private static byte[] getLengthBlock(int aLenInBytes, int cLenInBytes) {
+        long aLen = ((long)aLenInBytes) << 3;
+        long cLen = ((long)cLenInBytes) << 3;
         byte[] out = new byte[AES_BLOCK_SIZE];
+        out[0] = (byte)(aLen >>> 56);
+        out[1] = (byte)(aLen >>> 48);
+        out[2] = (byte)(aLen >>> 40);
+        out[3] = (byte)(aLen >>> 32);
         out[4] = (byte)(aLen >>> 24);
         out[5] = (byte)(aLen >>> 16);
         out[6] = (byte)(aLen >>> 8);
         out[7] = (byte)aLen;
+        out[8] = (byte)(cLen >>> 56);
+        out[9] = (byte)(cLen >>> 48);
+        out[10] = (byte)(cLen >>> 40);
+        out[11] = (byte)(cLen >>> 32);
         out[12] = (byte)(cLen >>> 24);
         out[13] = (byte)(cLen >>> 16);
         out[14] = (byte)(cLen >>> 8);
@@ -142,13 +165,20 @@
             } else {
                 g.update(iv);
             }
-            byte[] lengthBlock = getLengthBlock(iv.length*8);
+            byte[] lengthBlock = getLengthBlock(iv.length);
             g.update(lengthBlock);
             j0 = g.digest();
         }
         return j0;
     }
 
+    private static void checkDataLength(int processed, int len) {
+        if (processed > MAX_BUF_SIZE - len) {
+            throw new ProviderException("SunJCE provider only supports " +
+                "input size up to " + MAX_BUF_SIZE + " bytes");
+        }
+    }
+
     GaloisCounterMode(SymmetricCipher embeddedCipher) {
         super(embeddedCipher);
         aadBuffer = new ByteArrayOutputStream();
@@ -319,20 +349,22 @@
 
     // Feed the AAD data to GHASH, pad if necessary
     void processAAD() {
-        if (aadBuffer != null && aadBuffer.size() > 0) {
-            byte[] aad = aadBuffer.toByteArray();
-            sizeOfAAD = aad.length;
-            aadBuffer = null;
+        if (aadBuffer != null) {
+            if (aadBuffer.size() > 0) {
+                byte[] aad = aadBuffer.toByteArray();
+                sizeOfAAD = aad.length;
 
-            int lastLen = aad.length % AES_BLOCK_SIZE;
-            if (lastLen != 0) {
-                ghashAllToS.update(aad, 0, aad.length - lastLen);
-                byte[] padded = expandToOneBlock(aad, aad.length - lastLen,
-                                                 lastLen);
-                ghashAllToS.update(padded);
-            } else {
-                ghashAllToS.update(aad);
+                int lastLen = aad.length % AES_BLOCK_SIZE;
+                if (lastLen != 0) {
+                    ghashAllToS.update(aad, 0, aad.length - lastLen);
+                    byte[] padded = expandToOneBlock(aad, aad.length - lastLen,
+                                                     lastLen);
+                    ghashAllToS.update(padded);
+                } else {
+                    ghashAllToS.update(aad);
+                }
             }
+            aadBuffer = null;
         }
     }
 
@@ -384,6 +416,9 @@
         if ((len % blockSize) != 0) {
              throw new ProviderException("Internal error in input buffering");
         }
+
+        checkDataLength(processed, len);
+
         processAAD();
         if (len > 0) {
             gctrPAndC.update(in, inOfs, len, out, outOfs);
@@ -405,17 +440,23 @@
      */
     int encryptFinal(byte[] in, int inOfs, int len, byte[] out, int outOfs)
         throws IllegalBlockSizeException, ShortBufferException {
+        if (len > MAX_BUF_SIZE - tagLenBytes) {
+            throw new ShortBufferException
+                ("Can't fit both data and tag into one buffer");
+        }
         if (out.length - outOfs < (len + tagLenBytes)) {
             throw new ShortBufferException("Output buffer too small");
         }
 
+        checkDataLength(processed, len);
+
         processAAD();
         if (len > 0) {
             doLastBlock(in, inOfs, len, out, outOfs, true);
         }
 
         byte[] lengthBlock =
-            getLengthBlock(sizeOfAAD*8, processed*8);
+            getLengthBlock(sizeOfAAD, processed);
         ghashAllToS.update(lengthBlock);
         byte[] s = ghashAllToS.digest();
         byte[] sOut = new byte[s.length];
@@ -447,6 +488,9 @@
         if ((len % blockSize) != 0) {
              throw new ProviderException("Internal error in input buffering");
         }
+
+        checkDataLength(ibuffer.size(), len);
+
         processAAD();
 
         if (len > 0) {
@@ -481,10 +525,21 @@
         if (len < tagLenBytes) {
             throw new AEADBadTagException("Input too short - need tag");
         }
+        // do this check here can also catch the potential integer overflow
+        // scenario for the subsequent output buffer capacity check.
+        checkDataLength(ibuffer.size(), (len - tagLenBytes));
+
         if (out.length - outOfs < ((ibuffer.size() + len) - tagLenBytes)) {
             throw new ShortBufferException("Output buffer too small");
         }
+
         processAAD();
+
+        // get the trailing tag bytes from 'in'
+        byte[] tag = new byte[tagLenBytes];
+        System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes);
+        len -= tagLenBytes;
+
         if (len != 0) {
             ibuffer.write(in, inOfs, len);
         }
@@ -495,17 +550,12 @@
         len = in.length;
         ibuffer.reset();
 
-        byte[] tag = new byte[tagLenBytes];
-        // get the trailing tag bytes from 'in'
-        System.arraycopy(in, len - tagLenBytes, tag, 0, tagLenBytes);
-        len -= tagLenBytes;
-
         if (len > 0) {
             doLastBlock(in, inOfs, len, out, outOfs, false);
         }
 
         byte[] lengthBlock =
-            getLengthBlock(sizeOfAAD*8, processed*8);
+            getLengthBlock(sizeOfAAD, processed);
         ghashAllToS.update(lengthBlock);
 
         byte[] s = ghashAllToS.digest();
--- a/jdk/src/java.base/share/classes/com/sun/security/ntlm/Server.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/com/sun/security/ntlm/Server.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/classes/java/lang/Class.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java	Wed Jul 05 22:00:06 2017 +0200
@@ -238,15 +238,11 @@
 
             TypeVariable<?>[] typeparms = component.getTypeParameters();
             if (typeparms.length > 0) {
-                boolean first = true;
-                sb.append('<');
+                StringJoiner sj = new StringJoiner(",", "<", ">");
                 for(TypeVariable<?> typeparm: typeparms) {
-                    if (!first)
-                        sb.append(',');
-                    sb.append(typeparm.getTypeName());
-                    first = false;
+                    sj.add(typeparm.getTypeName());
                 }
-                sb.append('>');
+                sb.append(sj.toString());
             }
 
             for (int i = 0; i < arrayDepth; i++)
--- a/jdk/src/java.base/share/classes/java/lang/Runtime.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/Runtime.java	Wed Jul 05 22:00:06 2017 +0200
@@ -945,7 +945,7 @@
     }
 
     /**
-     * A representation of a version string for an implemenation of the
+     * A representation of a version string for an implementation of the
      * Java&nbsp;SE Platform.  A version string contains a version number
      * optionally followed by pre-release and build information.
      *
@@ -1058,10 +1058,10 @@
      * <p> When comparing two version strings, the value of {@code $OPT}, if
      * present, may or may not be significant depending on the chosen
      * comparison method.  The comparison methods {@link #compareTo(Version)
-     * compareTo()} and {@link #compareToIgnoreOpt(Version)
-     * compareToIgnoreOpt()} should be used consistently with the
+     * compareTo()} and {@link #compareToIgnoreOptional(Version)
+     * compareToIgnoreOptional()} should be used consistently with the
      * corresponding methods {@link #equals(Object) equals()} and {@link
-     * #equalsIgnoreOpt(Object) equalsIgnoreOpt()}.  </p>
+     * #equalsIgnoreOptional(Object) equalsIgnoreOptional()}.  </p>
      *
      * <p> A <em>short version string</em>, {@code $SVSTR}, often useful in
      * less formal contexts, is a version number optionally followed by a
@@ -1249,7 +1249,7 @@
          * @throws  NullPointerException
          *          If the given object is {@code null}
          */
-        public int compareToIgnoreOpt(Version ob) {
+        public int compareToIgnoreOptional(Version ob) {
             return compare(ob, true);
         }
 
@@ -1270,7 +1270,7 @@
                 return ret;
 
             if (!ignoreOpt)
-                return compareOpt(ob);
+                return compareOptional(ob);
 
             return 0;
         }
@@ -1325,7 +1325,7 @@
             return 0;
         }
 
-        private int compareOpt(Version ob) {
+        private int compareOptional(Version ob) {
             Optional<String> oOpt = ob.optional();
             if (!optional.isPresent()) {
                 if (oOpt.isPresent())
@@ -1384,7 +1384,7 @@
          */
         @Override
         public boolean equals(Object ob) {
-            boolean ret = equalsIgnoreOpt(ob);
+            boolean ret = equalsIgnoreOptional(ob);
             if (!ret)
                 return false;
 
@@ -1407,7 +1407,7 @@
          *          ignoring the optinal build information
          *
          */
-        public boolean equalsIgnoreOpt(Object ob) {
+        public boolean equalsIgnoreOptional(Object ob) {
             if (this == ob)
                 return true;
             if (!(ob instanceof Version))
--- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Wed Jul 05 22:00:06 2017 +0200
@@ -155,7 +155,7 @@
     private static LambdaForm preparedLambdaForm(MemberName m) {
         assert(m.isInvocable()) : m;  // call preparedFieldLambdaForm instead
         MethodType mtype = m.getInvocationType().basicType();
-        assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
+        assert(!m.isMethodHandleInvoke()) : m;
         int which;
         switch (m.getReferenceKind()) {
         case REF_invokeVirtual:    which = LF_INVVIRTUAL;    break;
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1049,7 +1049,7 @@
             this.member = member;
             this.resolvedHandle = resolvedHandle;
              // The following assert is almost always correct, but will fail for corner cases, such as PrivateInvokeTest.
-             //assert(!isInvokeBasic());
+             //assert(!isInvokeBasic(member));
         }
         NamedFunction(MethodType basicInvokerType) {
             assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
@@ -1060,13 +1060,13 @@
                 // necessary to pass BigArityTest
                 this.member = Invokers.invokeBasicMethod(basicInvokerType);
             }
-            assert(isInvokeBasic());
+            assert(isInvokeBasic(member));
         }
 
-        private boolean isInvokeBasic() {
+        private static boolean isInvokeBasic(MemberName member) {
             return member != null &&
-                   member.isMethodHandleInvoke() &&
-                   "invokeBasic".equals(member.getName());
+                   member.getDeclaringClass() == MethodHandle.class &&
+                  "invokeBasic".equals(member.getName());
         }
 
         // The next 2 constructors are used to break circular dependencies on MH.invokeStatic, etc.
@@ -1204,7 +1204,7 @@
             assert(mh.type().basicType() == MethodType.genericMethodType(arity).changeReturnType(rtype))
                     : Arrays.asList(mh, rtype, arity);
             MemberName member = mh.internalMemberName();
-            if (member != null && member.getName().equals("invokeBasic") && member.isMethodHandleInvoke()) {
+            if (isInvokeBasic(member)) {
                 assert(arity > 0);
                 assert(a[0] instanceof MethodHandle);
                 MethodHandle mh2 = (MethodHandle) a[0];
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java	Wed Jul 05 22:00:06 2017 +0200
@@ -346,7 +346,6 @@
     }
 
     /** Utility method to query if this member is a method handle invocation (invoke or invokeExact).
-     *  Also returns true for the non-public MH.invokeBasic.
      */
     public boolean isMethodHandleInvoke() {
         final int bits = MH_INVOKE_MODS &~ Modifier.PUBLIC;
@@ -361,7 +360,6 @@
         switch (name) {
         case "invoke":
         case "invokeExact":
-        case "invokeBasic":  // internal sig-poly method
             return true;
         default:
             return false;
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Jul 05 22:00:06 2017 +0200
@@ -951,8 +951,6 @@
                 return invoker(type);
             if ("invokeExact".equals(name))
                 return exactInvoker(type);
-            if ("invokeBasic".equals(name))
-                return basicInvoker(type);
             assert(!MemberName.isMethodHandleInvokeName(name));
             return null;
         }
@@ -3268,6 +3266,16 @@
      */
     public static
     MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
+        return dropArguments0(target, pos, copyTypes(valueTypes));
+    }
+
+    private static List<Class<?>> copyTypes(List<Class<?>> types) {
+        Object[] a = types.toArray();
+        return Arrays.asList(Arrays.copyOf(a, a.length, Class[].class));
+    }
+
+    private static
+    MethodHandle dropArguments0(MethodHandle target, int pos, List<Class<?>> valueTypes) {
         MethodType oldType = target.type();  // get NPE
         int dropped = dropArgumentChecks(oldType, pos, valueTypes);
         MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
@@ -3348,6 +3356,7 @@
     // private version which allows caller some freedom with error handling
     private static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos,
                                       boolean nullOnFailure) {
+        newTypes = copyTypes(newTypes);
         List<Class<?>> oldTypes = target.type().parameterList();
         int match = oldTypes.size();
         if (skip != 0) {
@@ -3379,11 +3388,11 @@
         // target: ( S*[skip],        M*[match]  )
         MethodHandle adapter = target;
         if (add > 0) {
-            adapter = dropArguments(adapter, skip+ match, addTypes);
+            adapter = dropArguments0(adapter, skip+ match, addTypes);
         }
         // adapter: (S*[skip],        M*[match], A*[add] )
         if (pos > 0) {
-            adapter = dropArguments(adapter, skip, newTypes.subList(0, pos));
+            adapter = dropArguments0(adapter, skip, newTypes.subList(0, pos));
        }
         // adapter: (S*[skip], P*[pos], M*[match], A*[add] )
         return adapter;
@@ -3787,7 +3796,7 @@
         int filterValues = filterType.parameterCount();
         if (filterValues == 0
                 ? (rtype != void.class)
-                : (rtype != filterType.parameterType(0)))
+                : (rtype != filterType.parameterType(0) || filterValues != 1))
             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
     }
 
@@ -4290,7 +4299,7 @@
                 step.set(i, dropArgumentsToMatch(identityOrVoid(t), 0, commonParameterSequence, i));
             }
             if (pred.get(i) == null) {
-                pred.set(i, dropArguments(constant(boolean.class, true), 0, commonParameterSequence));
+                pred.set(i, dropArguments0(constant(boolean.class, true), 0, commonParameterSequence));
             }
             if (fini.get(i) == null) {
                 fini.set(i, empty(methodType(t, commonParameterSequence)));
@@ -4315,7 +4324,7 @@
         return hs.stream().map(h -> {
             int pc = h.type().parameterCount();
             int tpsize = targetParams.size();
-            return pc < tpsize ? dropArguments(h, pc, targetParams.subList(pc, tpsize)) : h;
+            return pc < tpsize ? dropArguments0(h, pc, targetParams.subList(pc, tpsize)) : h;
         }).collect(Collectors.toList());
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Wed Jul 05 22:00:06 2017 +0200
@@ -52,6 +52,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -420,7 +421,7 @@
         // scan the entries in the JAR file to locate the .class and service
         // configuration file
         Map<Boolean, Set<String>> map =
-            jf.stream()
+            versionedStream(jf)
               .map(JarEntry::getName)
               .filter(s -> (s.endsWith(".class") ^ s.startsWith(SERVICES_PREFIX)))
               .collect(Collectors.partitioningBy(s -> s.endsWith(".class"),
@@ -503,8 +504,21 @@
         return mn;
     }
 
+    private Stream<JarEntry> versionedStream(JarFile jf) {
+        if (jf.isMultiRelease()) {
+            // a stream of JarEntries whose names are base names and whose
+            // contents are from the corresponding versioned entries in
+            // a multi-release jar file
+            return jf.stream().map(JarEntry::getName)
+                    .filter(name -> !name.startsWith("META-INF/versions/"))
+                    .map(jf::getJarEntry);
+        } else {
+            return jf.stream();
+        }
+    }
+
     private Set<String> jarPackages(JarFile jf) {
-        return jf.stream()
+        return versionedStream(jf)
             .filter(e -> e.getName().endsWith(".class"))
             .map(e -> toPackageName(e.getName()))
             .filter(pkg -> pkg.length() > 0)   // module-info
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 import java.lang.annotation.*;
 import java.util.Map;
 import java.util.Objects;
+import java.util.StringJoiner;
 
 import jdk.internal.misc.SharedSecrets;
 import sun.reflect.annotation.AnnotationParser;
@@ -86,15 +87,6 @@
                getDeclaringClass());
     }
 
-    void separateWithCommas(Class<?>[] types, StringBuilder sb) {
-        for (int j = 0; j < types.length; j++) {
-            sb.append(types[j].getTypeName());
-            if (j < (types.length - 1))
-                sb.append(",");
-        }
-
-    }
-
     void printModifiersIfNonzero(StringBuilder sb, int mask, boolean isDefault) {
         int mod = getModifiers() & mask;
 
@@ -121,13 +113,20 @@
 
             printModifiersIfNonzero(sb, modifierMask, isDefault);
             specificToStringHeader(sb);
-
             sb.append('(');
-            separateWithCommas(parameterTypes, sb);
+            StringJoiner sj = new StringJoiner(",");
+            for (Class<?> parameterType : parameterTypes) {
+                sj.add(parameterType.getTypeName());
+            }
+            sb.append(sj.toString());
             sb.append(')');
+
             if (exceptionTypes.length > 0) {
-                sb.append(" throws ");
-                separateWithCommas(exceptionTypes, sb);
+                StringJoiner joiner = new StringJoiner(",", "throws ", "");
+                for (Class<?> exceptionType : exceptionTypes) {
+                    joiner.add(exceptionType.getTypeName());
+                }
+                sb.append(joiner.toString());
             }
             return sb.toString();
         } catch (Exception e) {
@@ -149,42 +148,34 @@
 
             TypeVariable<?>[] typeparms = getTypeParameters();
             if (typeparms.length > 0) {
-                boolean first = true;
-                sb.append('<');
+                StringJoiner sj = new StringJoiner(",", "<", "> ");
                 for(TypeVariable<?> typeparm: typeparms) {
-                    if (!first)
-                        sb.append(',');
-                    // Class objects can't occur here; no need to test
-                    // and call Class.getName().
-                    sb.append(typeparm.toString());
-                    first = false;
+                    sj.add(typeparm.getTypeName());
                 }
-                sb.append("> ");
+                sb.append(sj.toString());
             }
 
             specificToGenericStringHeader(sb);
 
             sb.append('(');
+            StringJoiner sj = new StringJoiner(",");
             Type[] params = getGenericParameterTypes();
             for (int j = 0; j < params.length; j++) {
                 String param = params[j].getTypeName();
                 if (isVarArgs() && (j == params.length - 1)) // replace T[] with T...
                     param = param.replaceFirst("\\[\\]$", "...");
-                sb.append(param);
-                if (j < (params.length - 1))
-                    sb.append(',');
+                sj.add(param);
             }
+            sb.append(sj.toString());
             sb.append(')');
-            Type[] exceptions = getGenericExceptionTypes();
-            if (exceptions.length > 0) {
-                sb.append(" throws ");
-                for (int k = 0; k < exceptions.length; k++) {
-                    sb.append((exceptions[k] instanceof Class)?
-                              ((Class)exceptions[k]).getName():
-                              exceptions[k].toString());
-                    if (k < (exceptions.length - 1))
-                        sb.append(',');
+
+            Type[] exceptionTypes = getGenericExceptionTypes();
+            if (exceptionTypes.length > 0) {
+                StringJoiner joiner = new StringJoiner(",", " throws ", "");
+                for (Type exceptionType : exceptionTypes) {
+                    joiner.add(exceptionType.getTypeName());
                 }
+                sb.append(joiner.toString());
             }
             return sb.toString();
         } catch (Exception e) {
--- a/jdk/src/java.base/share/classes/java/net/URLPermission.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/URLPermission.java	Wed Jul 05 22:00:06 2017 +0200
@@ -461,11 +461,10 @@
     }
 
     private String actions() {
-        String b = String.join(",", methods);
-        if (!requestHeaders.isEmpty()) {
-            b += ":" + String.join(",", requestHeaders);
-        }
-        return b;
+        // The colon separator is optional when the request headers list is
+        // empty.This implementation chooses to include it even when the request
+        // headers list is empty.
+        return String.join(",", methods) + ":" + String.join(",", requestHeaders);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/security/ProtectionDomain.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/security/ProtectionDomain.java	Wed Jul 05 22:00:06 2017 +0200
@@ -132,7 +132,7 @@
 
     /* the PermissionCollection is static (pre 1.4 constructor)
        or dynamic (via a policy refresh) */
-    private boolean staticPermissions;
+    private final boolean staticPermissions;
 
     /*
      * An object used as a key when the ProtectionDomain is stored in a Map.
@@ -143,8 +143,12 @@
      * Creates a new ProtectionDomain with the given CodeSource and
      * Permissions. If the permissions object is not null, then
      *  {@code setReadOnly()} will be called on the passed in
-     * Permissions object. The only permissions granted to this domain
-     * are the ones specified; the current Policy will not be consulted.
+     * Permissions object.
+     * <p>
+     * The permissions granted to this domain are static, i.e.
+     * invoking the {@link #staticPermissionsOnly()} method returns true.
+     * They contain only the ones passed to this constructor and
+     * the current Policy will not be consulted.
      *
      * @param codesource the codesource associated with this domain
      * @param permissions the permissions granted to this domain
@@ -170,9 +174,11 @@
      * Permissions, ClassLoader and array of Principals. If the
      * permissions object is not null, then {@code setReadOnly()}
      * will be called on the passed in Permissions object.
-     * The permissions granted to this domain are dynamic; they include
-     * both the static permissions passed to this constructor, and any
-     * permissions granted to this domain by the current Policy at the
+     * <p>
+     * The permissions granted to this domain are dynamic, i.e.
+     * invoking the {@link #staticPermissionsOnly()} method returns false.
+     * They include both the static permissions passed to this constructor,
+     * and any permissions granted to this domain by the current Policy at the
      * time a permission is checked.
      * <p>
      * This constructor is typically used by
@@ -256,6 +262,19 @@
     }
 
     /**
+     * Returns true if this domain contains only static permissions
+     * and does not check the current {@code Policy} at the time of
+     * permission checking.
+     *
+     * @return true if this domain contains only static permissions.
+     *
+     * @since 9
+     */
+    public final boolean staticPermissionsOnly() {
+        return this.staticPermissions;
+    }
+
+    /**
      * Check and see if this ProtectionDomain implies the permissions
      * expressed in the Permission object.
      * <p>
@@ -263,25 +282,19 @@
      * ProtectionDomain was constructed with a static set of permissions
      * or it was bound to a dynamically mapped set of permissions.
      * <p>
-     * If the ProtectionDomain was constructed to a
-     * {@link #ProtectionDomain(CodeSource, PermissionCollection)
-     * statically bound} PermissionCollection then the permission will
-     * only be checked against the PermissionCollection supplied at
-     * construction.
+     * If the {@link #staticPermissionsOnly()} method returns
+     * true, then the permission will only be checked against the
+     * PermissionCollection supplied at construction.
      * <p>
-     * However, if the ProtectionDomain was constructed with
-     * the constructor variant which supports
-     * {@link #ProtectionDomain(CodeSource, PermissionCollection,
-     * ClassLoader, java.security.Principal[]) dynamically binding}
-     * permissions, then the permission will be checked against the
-     * combination of the PermissionCollection supplied at construction and
+     * Otherwise, the permission will be checked against the combination
+     * of the PermissionCollection supplied at construction and
      * the current Policy binding.
      *
-     * @param permission the Permission object to check.
+     * @param perm the Permission object to check.
      *
-     * @return true if "permission" is implicit to this ProtectionDomain.
+     * @return true if {@code perm} is implied by this ProtectionDomain.
      */
-    public boolean implies(Permission permission) {
+    public boolean implies(Permission perm) {
 
         if (hasAllPerm) {
             // internal permission collection already has AllPermission -
@@ -290,10 +303,10 @@
         }
 
         if (!staticPermissions &&
-            Policy.getPolicyNoCheck().implies(this, permission))
+            Policy.getPolicyNoCheck().implies(this, perm))
             return true;
         if (permissions != null)
-            return permissions.implies(permission);
+            return permissions.implies(perm);
 
         return false;
     }
--- a/jdk/src/java.base/share/classes/java/security/Provider.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/security/Provider.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/jdk/src/java.base/share/classes/java/util/Queue.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/Queue.java	Wed Jul 05 22:00:06 2017 +0200
@@ -124,7 +124,6 @@
  * always well-defined for queues with the same elements but different
  * ordering properties.
  *
- *
  * <p>This interface is a member of the
  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
--- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java	Wed Jul 05 22:00:06 2017 +0200
@@ -660,6 +660,7 @@
 
         // ResourceBundleProviders for loading ResourceBundles
         private ServiceLoader<ResourceBundleProvider> providers;
+        private boolean providersChecked;
 
         // Boolean.TRUE if the factory method caller provides a ResourceBundleProvier.
         private Boolean callerHasProvider;
@@ -675,7 +676,6 @@
                 this.loaderRef = new KeyElementReference<>(loader, referenceQueue, this);
             }
             this.moduleRef = new KeyElementReference<>(module, referenceQueue, this);
-            this.providers = getServiceLoader(module, baseName);
             calculateHashCode();
         }
 
@@ -712,11 +712,15 @@
         }
 
         ServiceLoader<ResourceBundleProvider> getProviders() {
+            if (!providersChecked) {
+                providers = getServiceLoader(getModule(), name);
+                providersChecked = true;
+            }
             return providers;
         }
 
         boolean hasProviders() {
-            return providers != null;
+            return getProviders() != null;
         }
 
         boolean callerHasProvider() {
@@ -789,8 +793,9 @@
                 }
                 clone.moduleRef = new KeyElementReference<>(getModule(),
                                                             referenceQueue, clone);
-                // Clear the reference to ResourceBundleProviders
+                // Clear the reference to ResourceBundleProviders and the flag
                 clone.providers = null;
+                clone.providersChecked = false;
                 // Clear the reference to a Throwable
                 clone.cause = null;
                 // Clear callerHasProvider
@@ -1841,6 +1846,9 @@
 
     private static ServiceLoader<ResourceBundleProvider> getServiceLoader(Module module,
                                                                           String baseName) {
+        if (!module.isNamed()) {
+            return null;
+        }
         PrivilegedAction<ClassLoader> pa = module::getClassLoader;
         ClassLoader loader = AccessController.doPrivileged(pa);
         return getServiceLoader(module, loader, baseName);
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.concurrent.locks.LockSupport;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
@@ -149,26 +151,29 @@
      * applies across normal vs exceptional outcomes, sync vs async
      * actions, binary triggers, and various forms of completions.
      *
-     * Non-nullness of field result (set via CAS) indicates done.  An
-     * AltResult is used to box null as a result, as well as to hold
-     * exceptions.  Using a single field makes completion simple to
-     * detect and trigger.  Encoding and decoding is straightforward
-     * but adds to the sprawl of trapping and associating exceptions
-     * with targets.  Minor simplifications rely on (static) NIL (to
-     * box null results) being the only AltResult with a null
-     * exception field, so we don't usually need explicit comparisons.
-     * Even though some of the generics casts are unchecked (see
-     * SuppressWarnings annotations), they are placed to be
-     * appropriate even if checked.
+     * Non-nullness of volatile field "result" indicates done.  It may
+     * be set directly if known to be thread-confined, else via CAS.
+     * An AltResult is used to box null as a result, as well as to
+     * hold exceptions.  Using a single field makes completion simple
+     * to detect and trigger.  Result encoding and decoding is
+     * straightforward but tedious and adds to the sprawl of trapping
+     * and associating exceptions with targets.  Minor simplifications
+     * rely on (static) NIL (to box null results) being the only
+     * AltResult with a null exception field, so we don't usually need
+     * explicit comparisons.  Even though some of the generics casts
+     * are unchecked (see SuppressWarnings annotations), they are
+     * placed to be appropriate even if checked.
      *
      * Dependent actions are represented by Completion objects linked
      * as Treiber stacks headed by field "stack". There are Completion
-     * classes for each kind of action, grouped into single-input
-     * (UniCompletion), two-input (BiCompletion), projected
-     * (BiCompletions using either (not both) of two inputs), shared
-     * (CoCompletion, used by the second of two sources), zero-input
-     * source actions, and Signallers that unblock waiters. Class
-     * Completion extends ForkJoinTask to enable async execution
+     * classes for each kind of action, grouped into:
+     * - single-input (UniCompletion),
+     * - two-input (BiCompletion),
+     * - projected (BiCompletions using exactly one of two inputs),
+     * - shared (CoCompletion, used by the second of two sources),
+     * - zero-input source actions,
+     * - Signallers that unblock waiters.
+     * Class Completion extends ForkJoinTask to enable async execution
      * (adding no space overhead because we exploit its "tag" methods
      * to maintain claims). It is also declared as Runnable to allow
      * usage with arbitrary executors.
@@ -184,7 +189,7 @@
      *   encounter layers of adapters in common usages.
      *
      * * Boolean CompletableFuture method x(...) (for example
-     *   uniApply) takes all of the arguments needed to check that an
+     *   biApply) takes all of the arguments needed to check that an
      *   action is triggerable, and then either runs the action or
      *   arranges its async execution by executing its Completion
      *   argument, if present. The method returns true if known to be
@@ -194,24 +199,32 @@
      *   method with its held arguments, and on success cleans up.
      *   The mode argument allows tryFire to be called twice (SYNC,
      *   then ASYNC); the first to screen and trap exceptions while
-     *   arranging to execute, and the second when called from a
-     *   task. (A few classes are not used async so take slightly
-     *   different forms.)  The claim() callback suppresses function
-     *   invocation if already claimed by another thread.
+     *   arranging to execute, and the second when called from a task.
+     *   (A few classes are not used async so take slightly different
+     *   forms.)  The claim() callback suppresses function invocation
+     *   if already claimed by another thread.
+     *
+     * * Some classes (for example UniApply) have separate handling
+     *   code for when known to be thread-confined ("now" methods) and
+     *   for when shared (in tryFire), for efficiency.
      *
      * * CompletableFuture method xStage(...) is called from a public
-     *   stage method of CompletableFuture x. It screens user
+     *   stage method of CompletableFuture f. It screens user
      *   arguments and invokes and/or creates the stage object.  If
-     *   not async and x is already complete, the action is run
-     *   immediately.  Otherwise a Completion c is created, pushed to
-     *   x's stack (unless done), and started or triggered via
-     *   c.tryFire.  This also covers races possible if x completes
-     *   while pushing.  Classes with two inputs (for example BiApply)
-     *   deal with races across both while pushing actions.  The
-     *   second completion is a CoCompletion pointing to the first,
-     *   shared so that at most one performs the action.  The
-     *   multiple-arity methods allOf and anyOf do this pairwise to
-     *   form trees of completions.
+     *   not async and already triggerable, the action is run
+     *   immediately.  Otherwise a Completion c is created, and
+     *   submitted to the executor if triggerable, or pushed onto f's
+     *   stack if not.  Completion actions are started via c.tryFire.
+     *   We recheck after pushing to a source future's stack to cover
+     *   possible races if the source completes while pushing.
+     *   Classes with two inputs (for example BiApply) deal with races
+     *   across both while pushing actions.  The second completion is
+     *   a CoCompletion pointing to the first, shared so that at most
+     *   one performs the action.  The multiple-arity methods allOf
+     *   does this pairwise to form trees of completions.  Method
+     *   anyOf is handled differently from allOf because completion of
+     *   any source should trigger a cleanStack of other sources.
+     *   Each AnyOf completion can reach others via a shared array.
      *
      * Note that the generic type parameters of methods vary according
      * to whether "this" is a source, dependent, or completion.
@@ -236,29 +249,30 @@
      * pointing back to its sources. So we null out fields as soon as
      * possible.  The screening checks needed anyway harmlessly ignore
      * null arguments that may have been obtained during races with
-     * threads nulling out fields.  We also try to unlink fired
-     * Completions from stacks that might never be popped (see method
-     * postFire).  Completion fields need not be declared as final or
-     * volatile because they are only visible to other threads upon
-     * safe publication.
+     * threads nulling out fields.  We also try to unlink non-isLive
+     * (fired or cancelled) Completions from stacks that might
+     * otherwise never be popped: Method cleanStack always unlinks non
+     * isLive completions from the head of stack; others may
+     * occasionally remain if racing with other cancellations or
+     * removals.
+     *
+     * Completion fields need not be declared as final or volatile
+     * because they are only visible to other threads upon safe
+     * publication.
      */
 
     volatile Object result;       // Either the result or boxed AltResult
     volatile Completion stack;    // Top of Treiber stack of dependent actions
 
     final boolean internalComplete(Object r) { // CAS from null to r
-        return U.compareAndSwapObject(this, RESULT, null, r);
-    }
-
-    final boolean casStack(Completion cmp, Completion val) {
-        return U.compareAndSwapObject(this, STACK, cmp, val);
+        return RESULT.compareAndSet(this, null, r);
     }
 
     /** Returns true if successfully pushed c onto stack. */
     final boolean tryPushStack(Completion c) {
         Completion h = stack;
-        lazySetNext(c, h);
-        return U.compareAndSwapObject(this, STACK, h, c);
+        NEXT.set(c, h);         // CAS piggyback
+        return STACK.compareAndSet(this, h, c);
     }
 
     /** Unconditionally pushes c onto stack, retrying if necessary. */
@@ -278,8 +292,7 @@
 
     /** Completes with the null value, unless already completed. */
     final boolean completeNull() {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      NIL);
+        return RESULT.compareAndSet(this, null, NIL);
     }
 
     /** Returns the encoding of the given non-exceptional value. */
@@ -289,8 +302,7 @@
 
     /** Completes with a non-exceptional result, unless already completed. */
     final boolean completeValue(T t) {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      (t == null) ? NIL : t);
+        return RESULT.compareAndSet(this, null, (t == null) ? NIL : t);
     }
 
     /**
@@ -304,8 +316,7 @@
 
     /** Completes with an exceptional result, unless already completed. */
     final boolean completeThrowable(Throwable x) {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      encodeThrowable(x));
+        return RESULT.compareAndSet(this, null, encodeThrowable(x));
     }
 
     /**
@@ -332,8 +343,7 @@
      * existing CompletionException.
      */
     final boolean completeThrowable(Throwable x, Object r) {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      encodeThrowable(x, r));
+        return RESULT.compareAndSet(this, null, encodeThrowable(x, r));
     }
 
     /**
@@ -351,10 +361,11 @@
      */
     static Object encodeRelay(Object r) {
         Throwable x;
-        return (((r instanceof AltResult) &&
-                 (x = ((AltResult)r).ex) != null &&
-                 !(x instanceof CompletionException)) ?
-                new AltResult(new CompletionException(x)) : r);
+        if (r instanceof AltResult
+            && (x = ((AltResult)r).ex) != null
+            && !(x instanceof CompletionException))
+            r = new AltResult(new CompletionException(x));
+        return r;
     }
 
     /**
@@ -362,14 +373,13 @@
      * If exceptional, r is first coerced to a CompletionException.
      */
     final boolean completeRelay(Object r) {
-        return U.compareAndSwapObject(this, RESULT, null,
-                                      encodeRelay(r));
+        return RESULT.compareAndSet(this, null, encodeRelay(r));
     }
 
     /**
      * Reports result using Future.get conventions.
      */
-    private static <T> T reportGet(Object r)
+    private static Object reportGet(Object r)
         throws InterruptedException, ExecutionException {
         if (r == null) // by convention below, null means interrupted
             throw new InterruptedException();
@@ -384,14 +394,13 @@
                 x = cause;
             throw new ExecutionException(x);
         }
-        @SuppressWarnings("unchecked") T t = (T) r;
-        return t;
+        return r;
     }
 
     /**
      * Decodes outcome to return result or throw unchecked exception.
      */
-    private static <T> T reportJoin(Object r) {
+    private static Object reportJoin(Object r) {
         if (r instanceof AltResult) {
             Throwable x;
             if ((x = ((AltResult)r).ex) == null)
@@ -402,8 +411,7 @@
                 throw (CompletionException)x;
             throw new CompletionException(x);
         }
-        @SuppressWarnings("unchecked") T t = (T) r;
-        return t;
+        return r;
     }
 
     /* ------------- Async task preliminaries -------------- */
@@ -449,12 +457,6 @@
     static final int ASYNC  =  1;
     static final int NESTED = -1;
 
-    /**
-     * Spins before blocking in waitingGet
-     */
-    static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ?
-                              1 << 8 : 0);
-
     /* ------------- Base Completion classes and operations -------------- */
 
     @SuppressWarnings("serial")
@@ -479,10 +481,6 @@
         public final void setRawResult(Void v) {}
     }
 
-    static void lazySetNext(Completion c, Completion next) {
-        U.putObjectRelease(c, NEXT, next);
-    }
-
     /**
      * Pops and tries to trigger all reachable dependents.  Call only
      * when known to be done.
@@ -497,40 +495,47 @@
         while ((h = f.stack) != null ||
                (f != this && (h = (f = this).stack) != null)) {
             CompletableFuture<?> d; Completion t;
-            if (f.casStack(h, t = h.next)) {
+            if (STACK.compareAndSet(f, h, t = h.next)) {
                 if (t != null) {
                     if (f != this) {
                         pushStack(h);
                         continue;
                     }
-                    h.next = null;    // detach
+                    NEXT.compareAndSet(h, t, null); // try to detach
                 }
                 f = (d = h.tryFire(NESTED)) == null ? this : d;
             }
         }
     }
 
-    /** Traverses stack and unlinks dead Completions. */
+    /** Traverses stack and unlinks one or more dead Completions, if found. */
     final void cleanStack() {
-        for (Completion p = null, q = stack; q != null;) {
+        Completion p = stack;
+        // ensure head of stack live
+        for (boolean unlinked = false;;) {
+            if (p == null)
+                return;
+            else if (p.isLive()) {
+                if (unlinked)
+                    return;
+                else
+                    break;
+            }
+            else if (STACK.weakCompareAndSetVolatile(this, p, (p = p.next)))
+                unlinked = true;
+            else
+                p = stack;
+        }
+        // try to unlink first non-live
+        for (Completion q = p.next; q != null;) {
             Completion s = q.next;
             if (q.isLive()) {
                 p = q;
                 q = s;
-            }
-            else if (p == null) {
-                casStack(q, s);
-                q = stack;
-            }
-            else {
-                p.next = s;
-                if (p.isLive())
-                    q = s;
-                else {
-                    p = null;  // restart
-                    q = stack;
-                }
-            }
+            } else if (NEXT.weakCompareAndSetVolatile(p, q, s))
+                break;
+            else
+                q = p.next;
         }
     }
 
@@ -568,24 +573,34 @@
         final boolean isLive() { return dep != null; }
     }
 
-    /** Pushes the given completion (if it exists) unless done. */
-    final void push(UniCompletion<?,?> c) {
+    /**
+     * Pushes the given completion unless it completes while trying.
+     * Caller should first check that result is null.
+     */
+    final void unipush(Completion c) {
         if (c != null) {
-            while (result == null && !tryPushStack(c))
-                lazySetNext(c, null); // clear on failure
+            while (!tryPushStack(c)) {
+                if (result != null) {
+                    NEXT.set(c, null);
+                    break;
+                }
+            }
+            if (result != null)
+                c.tryFire(SYNC);
         }
     }
 
     /**
-     * Post-processing by dependent after successful UniCompletion
-     * tryFire.  Tries to clean stack of source a, and then either runs
-     * postComplete or returns this to caller, depending on mode.
+     * Post-processing by dependent after successful UniCompletion tryFire.
+     * Tries to clean stack of source a, and then either runs postComplete
+     * or returns this to caller, depending on mode.
      */
     final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
         if (a != null && a.stack != null) {
-            if (a.result == null)
+            Object r;
+            if ((r = a.result) == null)
                 a.cleanStack();
-            else if (mode >= 0)
+            if (mode >= 0 && (r != null || a.result != null))
                 a.postComplete();
         }
         if (result != null && stack != null) {
@@ -607,48 +622,65 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniApply(a = src, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Function<? super T,? extends V> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else {
+                        @SuppressWarnings("unchecked") T t = (T) r;
+                        d.completeValue(f.apply(t));
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniApply(CompletableFuture<S> a,
-                               Function<? super S,? extends T> f,
-                               UniApply<S,T> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            if (r instanceof AltResult) {
-                if ((x = ((AltResult)r).ex) != null) {
-                    completeThrowable(x, r);
-                    break tryComplete;
-                }
-                r = null;
-            }
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                @SuppressWarnings("unchecked") S s = (S) r;
-                completeValue(f.apply(s));
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private <V> CompletableFuture<V> uniApplyStage(
         Executor e, Function<? super T,? extends V> f) {
         if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniApplyNow(r, e, f);
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e != null || !d.uniApply(this, f, null)) {
-            UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
+        unipush(new UniApply<T,V>(e, d, this, f));
+        return d;
+    }
+
+    private <V> CompletableFuture<V> uniApplyNow(
+        Object r, Executor e, Function<? super T,? extends V> f) {
+        Throwable x;
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (r instanceof AltResult) {
+            if ((x = ((AltResult)r).ex) != null) {
+                d.result = encodeThrowable(x, r);
+                return d;
+            }
+            r = null;
+        }
+        try {
+            if (e != null) {
+                e.execute(new UniApply<T,V>(null, d, this, f));
+            } else {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                d.result = d.encodeValue(f.apply(t));
+            }
+        } catch (Throwable ex) {
+            d.result = encodeThrowable(ex);
         }
         return d;
     }
@@ -662,48 +694,67 @@
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniAccept(a = src, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Consumer<? super T> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else {
+                        @SuppressWarnings("unchecked") T t = (T) r;
+                        f.accept(t);
+                        d.completeNull();
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniAccept(CompletableFuture<S> a,
-                                Consumer<? super S> f, UniAccept<S> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            if (r instanceof AltResult) {
-                if ((x = ((AltResult)r).ex) != null) {
-                    completeThrowable(x, r);
-                    break tryComplete;
-                }
-                r = null;
-            }
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                @SuppressWarnings("unchecked") S s = (S) r;
-                f.accept(s);
-                completeNull();
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private CompletableFuture<Void> uniAcceptStage(Executor e,
                                                    Consumer<? super T> f) {
         if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniAcceptNow(r, e, f);
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.uniAccept(this, f, null)) {
-            UniAccept<T> c = new UniAccept<T>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
+        unipush(new UniAccept<T>(e, d, this, f));
+        return d;
+    }
+
+    private CompletableFuture<Void> uniAcceptNow(
+        Object r, Executor e, Consumer<? super T> f) {
+        Throwable x;
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (r instanceof AltResult) {
+            if ((x = ((AltResult)r).ex) != null) {
+                d.result = encodeThrowable(x, r);
+                return d;
+            }
+            r = null;
+        }
+        try {
+            if (e != null) {
+                e.execute(new UniAccept<T>(null, d, this, f));
+            } else {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                f.accept(t);
+                d.result = NIL;
+            }
+        } catch (Throwable ex) {
+            d.result = encodeThrowable(ex);
         }
         return d;
     }
@@ -717,42 +768,56 @@
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniRun(a = src, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Runnable f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            if (d.result == null) {
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                    d.completeThrowable(x, r);
+                else
+                    try {
+                        if (mode <= 0 && !claim())
+                            return null;
+                        else {
+                            f.run();
+                            d.completeNull();
+                        }
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
-        if (result == null) {
-            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                completeThrowable(x, r);
-            else
-                try {
-                    if (c != null && !c.claim())
-                        return false;
-                    f.run();
-                    completeNull();
-                } catch (Throwable ex) {
-                    completeThrowable(ex);
-                }
-        }
-        return true;
+    private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniRunNow(r, e, f);
+        CompletableFuture<Void> d = newIncompleteFuture();
+        unipush(new UniRun<T>(e, d, this, f));
+        return d;
     }
 
-    private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
-        if (f == null) throw new NullPointerException();
+    private CompletableFuture<Void> uniRunNow(Object r, Executor e, Runnable f) {
+        Throwable x;
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.uniRun(this, f, null)) {
-            UniRun<T> c = new UniRun<T>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
-        }
+        if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+            d.result = encodeThrowable(x, r);
+        else
+            try {
+                if (e != null) {
+                    e.execute(new UniRun<T>(null, d, this, f));
+                } else {
+                    f.run();
+                    d.result = NIL;
+                }
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
@@ -766,20 +831,20 @@
         }
         final CompletableFuture<T> tryFire(int mode) {
             CompletableFuture<T> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
+            Object r; BiConsumer<? super T, ? super Throwable> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || !d.uniWhenComplete(r, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniWhenComplete(CompletableFuture<T> a,
+    final boolean uniWhenComplete(Object r,
                                   BiConsumer<? super T,? super Throwable> f,
                                   UniWhenComplete<T> c) {
-        Object r; T t; Throwable x = null;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
+        T t; Throwable x = null;
         if (result == null) {
             try {
                 if (c != null && !c.claim())
@@ -811,10 +876,17 @@
         Executor e, BiConsumer<? super T, ? super Throwable> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<T> d = newIncompleteFuture();
-        if (e != null || !d.uniWhenComplete(this, f, null)) {
-            UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniWhenComplete<T>(e, d, this, f));
+        else if (e == null)
+            d.uniWhenComplete(r, f, null);
+        else {
+            try {
+                e.execute(new UniWhenComplete<T>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         }
         return d;
     }
@@ -829,20 +901,20 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniHandle(a = src, fn, mode > 0 ? null : this))
+            Object r; BiFunction<? super T, Throwable, ? extends V> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || !d.uniHandle(r, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniHandle(CompletableFuture<S> a,
+    final <S> boolean uniHandle(Object r,
                                 BiFunction<? super S, Throwable, ? extends T> f,
                                 UniHandle<S,T> c) {
-        Object r; S s; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
+        S s; Throwable x;
         if (result == null) {
             try {
                 if (c != null && !c.claim())
@@ -867,10 +939,17 @@
         Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e != null || !d.uniHandle(this, f, null)) {
-            UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
-            push(c);
-            c.tryFire(SYNC);
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniHandle<T,V>(e, d, this, f));
+        else if (e == null)
+            d.uniHandle(r, f, null);
+        else {
+            try {
+                e.execute(new UniHandle<T,V>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         }
         return d;
     }
@@ -885,19 +964,20 @@
         final CompletableFuture<T> tryFire(int mode) { // never ASYNC
             // assert mode != ASYNC;
             CompletableFuture<T> d; CompletableFuture<T> a;
-            if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
+            Object r; Function<? super Throwable, ? extends T> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || !d.uniExceptionally(r, f, this))
                 return null;
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniExceptionally(CompletableFuture<T> a,
+    final boolean uniExceptionally(Object r,
                                    Function<? super Throwable, ? extends T> f,
                                    UniExceptionally<T> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
+        Throwable x;
         if (result == null) {
             try {
                 if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
@@ -917,47 +997,39 @@
         Function<Throwable, ? extends T> f) {
         if (f == null) throw new NullPointerException();
         CompletableFuture<T> d = newIncompleteFuture();
-        if (!d.uniExceptionally(this, f, null)) {
-            UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
-            push(c);
-            c.tryFire(SYNC);
-        }
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniExceptionally<T>(d, this, f));
+        else
+            d.uniExceptionally(r, f, null);
         return d;
     }
 
     @SuppressWarnings("serial")
-    static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
-        UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+    static final class UniRelay<U, T extends U> extends UniCompletion<T,U> {
+        UniRelay(CompletableFuture<U> dep, CompletableFuture<T> src) {
             super(null, dep, src);
         }
-        final CompletableFuture<T> tryFire(int mode) {
-            CompletableFuture<T> d; CompletableFuture<T> a;
-            if ((d = dep) == null || !d.uniRelay(a = src))
+        final CompletableFuture<U> tryFire(int mode) {
+            CompletableFuture<U> d; CompletableFuture<T> a; Object r;
+            if ((d = dep) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            if (d.result == null)
+                d.completeRelay(r);
             src = null; dep = null;
             return d.postFire(a, mode);
         }
     }
 
-    final boolean uniRelay(CompletableFuture<T> a) {
+    private static <U, T extends U> CompletableFuture<U> uniCopyStage(
+        CompletableFuture<T> src) {
         Object r;
-        if (a == null || (r = a.result) == null)
-            return false;
-        if (result == null) // no need to claim
-            completeRelay(r);
-        return true;
-    }
-
-    private CompletableFuture<T> uniCopyStage() {
-        Object r;
-        CompletableFuture<T> d = newIncompleteFuture();
-        if ((r = result) != null)
-            d.completeRelay(r);
-        else {
-            UniRelay<T> c = new UniRelay<T>(d, this);
-            push(c);
-            c.tryFire(SYNC);
-        }
+        CompletableFuture<U> d = src.newIncompleteFuture();
+        if ((r = src.result) != null)
+            d.result = encodeRelay(r);
+        else
+            src.unipush(new UniRelay<U,T>(d, src));
         return d;
     }
 
@@ -966,9 +1038,7 @@
         if ((r = result) != null)
             return new MinimalStage<T>(encodeRelay(r));
         MinimalStage<T> d = new MinimalStage<T>();
-        UniRelay<T> c = new UniRelay<T>(d, this);
-        push(c);
-        c.tryFire(SYNC);
+        unipush(new UniRelay<T,T>(d, this));
         return d;
     }
 
@@ -982,54 +1052,48 @@
         }
         final CompletableFuture<V> tryFire(int mode) {
             CompletableFuture<V> d; CompletableFuture<T> a;
-            if ((d = dep) == null ||
-                !d.uniCompose(a = src, fn, mode > 0 ? null : this))
+            Function<? super T, ? extends CompletionStage<V>> f;
+            Object r; Throwable x;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null)
                 return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    CompletableFuture<V> g = f.apply(t).toCompletableFuture();
+                    if ((r = g.result) != null)
+                        d.completeRelay(r);
+                    else {
+                        g.unipush(new UniRelay<V,V>(d, g));
+                        if (d.result == null)
+                            return null;
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; fn = null;
             return d.postFire(a, mode);
         }
     }
 
-    final <S> boolean uniCompose(
-        CompletableFuture<S> a,
-        Function<? super S, ? extends CompletionStage<T>> f,
-        UniCompose<S,T> c) {
-        Object r; Throwable x;
-        if (a == null || (r = a.result) == null || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            if (r instanceof AltResult) {
-                if ((x = ((AltResult)r).ex) != null) {
-                    completeThrowable(x, r);
-                    break tryComplete;
-                }
-                r = null;
-            }
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                @SuppressWarnings("unchecked") S s = (S) r;
-                CompletableFuture<T> g = f.apply(s).toCompletableFuture();
-                if (g.result == null || !uniRelay(g)) {
-                    UniRelay<T> copy = new UniRelay<T>(this, g);
-                    g.push(copy);
-                    copy.tryFire(SYNC);
-                    if (result == null)
-                        return false;
-                }
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private <V> CompletableFuture<V> uniComposeStage(
         Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
         if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
         Object r, s; Throwable x;
-        CompletableFuture<V> d = newIncompleteFuture();
-        if (e == null && (r = result) != null) {
+        if ((r = result) == null)
+            unipush(new UniCompose<T,V>(e, d, this, f));
+        else if (e == null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
                     d.result = encodeThrowable(x, r);
@@ -1041,21 +1105,20 @@
                 @SuppressWarnings("unchecked") T t = (T) r;
                 CompletableFuture<V> g = f.apply(t).toCompletableFuture();
                 if ((s = g.result) != null)
-                    d.completeRelay(s);
+                    d.result = encodeRelay(s);
                 else {
-                    UniRelay<V> c = new UniRelay<V>(d, g);
-                    g.push(c);
-                    c.tryFire(SYNC);
+                    g.unipush(new UniRelay<V,V>(d, g));
                 }
-                return d;
             } catch (Throwable ex) {
                 d.result = encodeThrowable(ex);
-                return d;
             }
         }
-        UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
-        push(c);
-        c.tryFire(SYNC);
+        else
+            try {
+                e.execute(new UniCompose<T,V>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
@@ -1085,21 +1148,28 @@
         }
         final boolean isLive() {
             BiCompletion<?,?,?> c;
-            return (c = base) != null && c.dep != null;
+            return (c = base) != null
+                // && c.isLive()
+                && c.dep != null;
         }
     }
 
-    /** Pushes completion to this and b unless both done. */
+    /**
+     * Pushes completion to this and b unless both done.
+     * Caller should first check that either result or b.result is null.
+     */
     final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
         if (c != null) {
-            Object r;
-            while ((r = result) == null && !tryPushStack(c))
-                lazySetNext(c, null); // clear on failure
-            if (b != null && b != this && b.result == null) {
-                Completion q = (r != null) ? c : new CoCompletion(c);
-                while (b.result == null && !b.tryPushStack(q))
-                    lazySetNext(q, null); // clear on failure
+            while (result == null) {
+                if (tryPushStack(c)) {
+                    if (b.result == null)
+                        b.unipush(new CoCompletion(c));
+                    else if (result != null)
+                        c.tryFire(SYNC);
+                    return;
+                }
             }
+            b.unipush(c);
         }
     }
 
@@ -1107,9 +1177,10 @@
     final CompletableFuture<T> postFire(CompletableFuture<?> a,
                                         CompletableFuture<?> b, int mode) {
         if (b != null && b.stack != null) { // clean second source
-            if (b.result == null)
+            Object r;
+            if ((r = b.result) == null)
                 b.cleanStack();
-            else if (mode >= 0)
+            if (mode >= 0 && (r != null || b.result != null))
                 b.postComplete();
         }
         return postFire(a, mode);
@@ -1127,22 +1198,21 @@
             CompletableFuture<V> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r, s; BiFunction<? super T,? super U,? extends V> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || !d.biApply(r, s, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S> boolean biApply(CompletableFuture<R> a,
-                                CompletableFuture<S> b,
+    final <R,S> boolean biApply(Object r, Object s,
                                 BiFunction<? super R,? super S,? extends T> f,
                                 BiApply<R,S,T> c) {
-        Object r, s; Throwable x;
-        if (a == null || (r = a.result) == null ||
-            b == null || (s = b.result) == null || f == null)
-            return false;
+        Throwable x;
         tryComplete: if (result == null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
@@ -1174,15 +1244,20 @@
     private <U,V> CompletableFuture<V> biApplyStage(
         Executor e, CompletionStage<U> o,
         BiFunction<? super T,? super U,? extends V> f) {
-        CompletableFuture<U> b;
+        CompletableFuture<U> b; Object r, s;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e != null || !d.biApply(this, b, f, null)) {
-            BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
-            bipush(b, c);
-            c.tryFire(SYNC);
-        }
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiApply<T,U,V>(e, d, this, b, f));
+        else if (e == null)
+            d.biApply(r, s, f, null);
+        else
+            try {
+                e.execute(new BiApply<T,U,V>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
@@ -1198,22 +1273,21 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r, s; BiConsumer<? super T,? super U> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || !d.biAccept(r, s, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S> boolean biAccept(CompletableFuture<R> a,
-                                 CompletableFuture<S> b,
+    final <R,S> boolean biAccept(Object r, Object s,
                                  BiConsumer<? super R,? super S> f,
                                  BiAccept<R,S> c) {
-        Object r, s; Throwable x;
-        if (a == null || (r = a.result) == null ||
-            b == null || (s = b.result) == null || f == null)
-            return false;
+        Throwable x;
         tryComplete: if (result == null) {
             if (r instanceof AltResult) {
                 if ((x = ((AltResult)r).ex) != null) {
@@ -1246,15 +1320,20 @@
     private <U> CompletableFuture<Void> biAcceptStage(
         Executor e, CompletionStage<U> o,
         BiConsumer<? super T,? super U> f) {
-        CompletableFuture<U> b;
+        CompletableFuture<U> b; Object r, s;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.biAccept(this, b, f, null)) {
-            BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
-            bipush(b, c);
-            c.tryFire(SYNC);
-        }
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiAccept<T,U>(e, d, this, b, f));
+        else if (e == null)
+            d.biAccept(r, s, f, null);
+        else
+            try {
+                e.execute(new BiAccept<T,U>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
@@ -1262,8 +1341,7 @@
     static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
         Runnable fn;
         BiRun(Executor executor, CompletableFuture<Void> dep,
-              CompletableFuture<T> src,
-              CompletableFuture<U> snd,
+              CompletableFuture<T> src, CompletableFuture<U> snd,
               Runnable fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1271,25 +1349,25 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r, s; Runnable f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || !d.biRun(r, s, f, mode > 0 ? null : this))
                 return null;
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
-                        Runnable f, BiRun<?,?> c) {
-        Object r, s; Throwable x;
-        if (a == null || (r = a.result) == null ||
-            b == null || (s = b.result) == null || f == null)
-            return false;
+    final boolean biRun(Object r, Object s, Runnable f, BiRun<?,?> c) {
+        Throwable x; Object z;
         if (result == null) {
-            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                completeThrowable(x, r);
-            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
-                completeThrowable(x, s);
+            if ((r instanceof AltResult
+                 && (x = ((AltResult)(z = r)).ex) != null) ||
+                (s instanceof AltResult
+                 && (x = ((AltResult)(z = s)).ex) != null))
+                completeThrowable(x, z);
             else
                 try {
                     if (c != null && !c.claim())
@@ -1305,52 +1383,52 @@
 
     private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
                                                Runnable f) {
-        CompletableFuture<?> b;
+        CompletableFuture<?> b; Object r, s;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.biRun(this, b, f, null)) {
-            BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
-            bipush(b, c);
-            c.tryFire(SYNC);
-        }
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiRun<>(e, d, this, b, f));
+        else if (e == null)
+            d.biRun(r, s, f, null);
+        else
+            try {
+                e.execute(new BiRun<>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
         return d;
     }
 
     @SuppressWarnings("serial")
     static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
         BiRelay(CompletableFuture<Void> dep,
-                CompletableFuture<T> src,
-                CompletableFuture<U> snd) {
+                CompletableFuture<T> src, CompletableFuture<U> snd) {
             super(null, dep, src, snd);
         }
         final CompletableFuture<Void> tryFire(int mode) {
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null || !d.biRelay(a = src, b = snd))
+            Object r, s, z; Throwable x;
+            if ((d = dep) == null
+                || (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null)
                 return null;
+            if (d.result == null) {
+                if ((r instanceof AltResult
+                     && (x = ((AltResult)(z = r)).ex) != null) ||
+                    (s instanceof AltResult
+                     && (x = ((AltResult)(z = s)).ex) != null))
+                    d.completeThrowable(x, z);
+                else
+                    d.completeNull();
+            }
             src = null; snd = null; dep = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
-        Object r, s; Throwable x;
-        if (a == null || (r = a.result) == null ||
-            b == null || (s = b.result) == null)
-            return false;
-        if (result == null) {
-            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                completeThrowable(x, r);
-            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
-                completeThrowable(x, s);
-            else
-                completeNull();
-        }
-        return true;
-    }
-
     /** Recursively constructs a tree of completions. */
     static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
                                            int lo, int hi) {
@@ -1358,39 +1436,44 @@
         if (lo > hi) // empty
             d.result = NIL;
         else {
-            CompletableFuture<?> a, b;
+            CompletableFuture<?> a, b; Object r, s, z; Throwable x;
             int mid = (lo + hi) >>> 1;
             if ((a = (lo == mid ? cfs[lo] :
                       andTree(cfs, lo, mid))) == null ||
                 (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
                       andTree(cfs, mid+1, hi))) == null)
                 throw new NullPointerException();
-            if (!d.biRelay(a, b)) {
-                BiRelay<?,?> c = new BiRelay<>(d, a, b);
-                a.bipush(b, c);
-                c.tryFire(SYNC);
-            }
+            if ((r = a.result) == null || (s = b.result) == null)
+                a.bipush(b, new BiRelay<>(d, a, b));
+            else if ((r instanceof AltResult
+                      && (x = ((AltResult)(z = r)).ex) != null) ||
+                     (s instanceof AltResult
+                      && (x = ((AltResult)(z = s)).ex) != null))
+                d.result = encodeThrowable(x, z);
+            else
+                d.result = NIL;
         }
         return d;
     }
 
     /* ------------- Projected (Ored) BiCompletions -------------- */
 
-    /** Pushes completion to this and b unless either done. */
+    /**
+     * Pushes completion to this and b unless either done.
+     * Caller should first check that result and b.result are both null.
+     */
     final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
         if (c != null) {
-            while ((b == null || b.result == null) && result == null) {
-                if (tryPushStack(c)) {
-                    if (b != null && b != this && b.result == null) {
-                        Completion q = new CoCompletion(c);
-                        while (result == null && b.result == null &&
-                               !b.tryPushStack(q))
-                            lazySetNext(q, null); // clear on failure
-                    }
+            while (!tryPushStack(c)) {
+                if (result != null) {
+                    NEXT.set(c, null);
                     break;
                 }
-                lazySetNext(c, null); // clear on failure
             }
+            if (result != null)
+                c.tryFire(SYNC);
+            else
+                b.unipush(new CoCompletion(c));
         }
     }
 
@@ -1398,8 +1481,7 @@
     static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
         Function<? super T,? extends V> fn;
         OrApply(Executor executor, CompletableFuture<V> dep,
-                CompletableFuture<T> src,
-                CompletableFuture<U> snd,
+                CompletableFuture<T> src, CompletableFuture<U> snd,
                 Function<? super T,? extends V> fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1407,54 +1489,46 @@
             CompletableFuture<V> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Function<? super T,? extends V> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null))
                 return null;
+            tryComplete: if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    if (r instanceof AltResult) {
+                        if ((x = ((AltResult)r).ex) != null) {
+                            d.completeThrowable(x, r);
+                            break tryComplete;
+                        }
+                        r = null;
+                    }
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    d.completeValue(f.apply(t));
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S extends R> boolean orApply(CompletableFuture<R> a,
-                                          CompletableFuture<S> b,
-                                          Function<? super R, ? extends T> f,
-                                          OrApply<R,S,T> c) {
-        Object r; Throwable x;
-        if (a == null || b == null ||
-            ((r = a.result) == null && (r = b.result) == null) || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                if (r instanceof AltResult) {
-                    if ((x = ((AltResult)r).ex) != null) {
-                        completeThrowable(x, r);
-                        break tryComplete;
-                    }
-                    r = null;
-                }
-                @SuppressWarnings("unchecked") R rr = (R) r;
-                completeValue(f.apply(rr));
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private <U extends T,V> CompletableFuture<V> orApplyStage(
-        Executor e, CompletionStage<U> o,
-        Function<? super T, ? extends V> f) {
+        Executor e, CompletionStage<U> o, Function<? super T, ? extends V> f) {
         CompletableFuture<U> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
+
+        Object r; CompletableFuture<? extends T> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniApplyNow(r, e, f);
+
         CompletableFuture<V> d = newIncompleteFuture();
-        if (e != null || !d.orApply(this, b, f, null)) {
-            OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
-            orpush(b, c);
-            c.tryFire(SYNC);
-        }
+        orpush(b, new OrApply<T,U,V>(e, d, this, b, f));
         return d;
     }
 
@@ -1462,8 +1536,7 @@
     static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
         Consumer<? super T> fn;
         OrAccept(Executor executor, CompletableFuture<Void> dep,
-                 CompletableFuture<T> src,
-                 CompletableFuture<U> snd,
+                 CompletableFuture<T> src, CompletableFuture<U> snd,
                  Consumer<? super T> fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1471,54 +1544,47 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Consumer<? super T> f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null))
                 return null;
+            tryComplete: if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    if (r instanceof AltResult) {
+                        if ((x = ((AltResult)r).ex) != null) {
+                            d.completeThrowable(x, r);
+                            break tryComplete;
+                        }
+                        r = null;
+                    }
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    f.accept(t);
+                    d.completeNull();
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
-                                           CompletableFuture<S> b,
-                                           Consumer<? super R> f,
-                                           OrAccept<R,S> c) {
-        Object r; Throwable x;
-        if (a == null || b == null ||
-            ((r = a.result) == null && (r = b.result) == null) || f == null)
-            return false;
-        tryComplete: if (result == null) {
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                if (r instanceof AltResult) {
-                    if ((x = ((AltResult)r).ex) != null) {
-                        completeThrowable(x, r);
-                        break tryComplete;
-                    }
-                    r = null;
-                }
-                @SuppressWarnings("unchecked") R rr = (R) r;
-                f.accept(rr);
-                completeNull();
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private <U extends T> CompletableFuture<Void> orAcceptStage(
         Executor e, CompletionStage<U> o, Consumer<? super T> f) {
         CompletableFuture<U> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
+
+        Object r; CompletableFuture<? extends T> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniAcceptNow(r, e, f);
+
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.orAccept(this, b, f, null)) {
-            OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
-            orpush(b, c);
-            c.tryFire(SYNC);
-        }
+        orpush(b, new OrAccept<T,U>(e, d, this, b, f));
         return d;
     }
 
@@ -1526,8 +1592,7 @@
     static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
         Runnable fn;
         OrRun(Executor executor, CompletableFuture<Void> dep,
-              CompletableFuture<T> src,
-              CompletableFuture<U> snd,
+              CompletableFuture<T> src, CompletableFuture<U> snd,
               Runnable fn) {
             super(executor, dep, src, snd); this.fn = fn;
         }
@@ -1535,97 +1600,81 @@
             CompletableFuture<Void> d;
             CompletableFuture<T> a;
             CompletableFuture<U> b;
-            if ((d = dep) == null ||
-                !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
+            Object r; Throwable x; Runnable f;
+            if ((d = dep) == null || (f = fn) == null
+                || (a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null))
                 return null;
+            if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else if (r instanceof AltResult
+                        && (x = ((AltResult)r).ex) != null)
+                        d.completeThrowable(x, r);
+                    else {
+                        f.run();
+                        d.completeNull();
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
             dep = null; src = null; snd = null; fn = null;
             return d.postFire(a, b, mode);
         }
     }
 
-    final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
-                        Runnable f, OrRun<?,?> c) {
-        Object r; Throwable x;
-        if (a == null || b == null ||
-            ((r = a.result) == null && (r = b.result) == null) || f == null)
-            return false;
-        if (result == null) {
-            try {
-                if (c != null && !c.claim())
-                    return false;
-                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
-                    completeThrowable(x, r);
-                else {
-                    f.run();
-                    completeNull();
-                }
-            } catch (Throwable ex) {
-                completeThrowable(ex);
-            }
-        }
-        return true;
-    }
-
     private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
                                                Runnable f) {
         CompletableFuture<?> b;
         if (f == null || (b = o.toCompletableFuture()) == null)
             throw new NullPointerException();
+
+        Object r; CompletableFuture<?> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniRunNow(r, e, f);
+
         CompletableFuture<Void> d = newIncompleteFuture();
-        if (e != null || !d.orRun(this, b, f, null)) {
-            OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
-            orpush(b, c);
-            c.tryFire(SYNC);
-        }
+        orpush(b, new OrRun<>(e, d, this, b, f));
         return d;
     }
 
+    /** Completion for an anyOf input future. */
     @SuppressWarnings("serial")
-    static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
-        OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
-                CompletableFuture<U> snd) {
-            super(null, dep, src, snd);
+    static class AnyOf extends Completion {
+        CompletableFuture<Object> dep; CompletableFuture<?> src;
+        CompletableFuture<?>[] srcs;
+        AnyOf(CompletableFuture<Object> dep, CompletableFuture<?> src,
+              CompletableFuture<?>[] srcs) {
+            this.dep = dep; this.src = src; this.srcs = srcs;
         }
         final CompletableFuture<Object> tryFire(int mode) {
-            CompletableFuture<Object> d;
-            CompletableFuture<T> a;
-            CompletableFuture<U> b;
-            if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+            // assert mode != ASYNC;
+            CompletableFuture<Object> d; CompletableFuture<?> a;
+            CompletableFuture<?>[] as;
+            Object r;
+            if ((d = dep) == null
+                || (a = src) == null || (r = a.result) == null
+                || (as = srcs) == null)
                 return null;
-            src = null; snd = null; dep = null;
-            return d.postFire(a, b, mode);
+            dep = null; src = null; srcs = null;
+            if (d.completeRelay(r)) {
+                for (CompletableFuture<?> b : as)
+                    if (b != a)
+                        b.cleanStack();
+                if (mode < 0)
+                    return d;
+                else
+                    d.postComplete();
+            }
+            return null;
         }
-    }
-
-    final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
-        Object r;
-        if (a == null || b == null ||
-            ((r = a.result) == null && (r = b.result) == null))
-            return false;
-        if (result == null)
-            completeRelay(r);
-        return true;
-    }
-
-    /** Recursively constructs a tree of completions. */
-    static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
-                                            int lo, int hi) {
-        CompletableFuture<Object> d = new CompletableFuture<Object>();
-        if (lo <= hi) {
-            CompletableFuture<?> a, b;
-            int mid = (lo + hi) >>> 1;
-            if ((a = (lo == mid ? cfs[lo] :
-                      orTree(cfs, lo, mid))) == null ||
-                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
-                      orTree(cfs, mid+1, hi))) == null)
-                throw new NullPointerException();
-            if (!d.orRelay(a, b)) {
-                OrRelay<?,?> c = new OrRelay<>(d, a, b);
-                a.orpush(b, c);
-                c.tryFire(SYNC);
-            }
+        final boolean isLive() {
+            CompletableFuture<Object> d;
+            return (d = dep) != null && d.result == null;
         }
-        return d;
     }
 
     /* ------------- Zero-input Async forms -------------- */
@@ -1640,7 +1689,7 @@
 
         public final Void getRawResult() { return null; }
         public final void setRawResult(Void v) {}
-        public final boolean exec() { run(); return true; }
+        public final boolean exec() { run(); return false; }
 
         public void run() {
             CompletableFuture<T> d; Supplier<? extends T> f;
@@ -1676,7 +1725,7 @@
 
         public final Void getRawResult() { return null; }
         public final void setRawResult(Void v) {}
-        public final boolean exec() { run(); return true; }
+        public final boolean exec() { run(); return false; }
 
         public void run() {
             CompletableFuture<Void> d; Runnable f;
@@ -1760,15 +1809,13 @@
     private Object waitingGet(boolean interruptible) {
         Signaller q = null;
         boolean queued = false;
-        int spins = SPINS;
         Object r;
         while ((r = result) == null) {
-            if (spins > 0) {
-                if (ThreadLocalRandom.nextSecondarySeed() >= 0)
-                    --spins;
+            if (q == null) {
+                q = new Signaller(interruptible, 0L, 0L);
+                if (Thread.currentThread() instanceof ForkJoinWorkerThread)
+                    ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
             }
-            else if (q == null)
-                q = new Signaller(interruptible, 0L, 0L);
             else if (!queued)
                 queued = tryPushStack(q);
             else {
@@ -1781,16 +1828,14 @@
                     break;
             }
         }
-        if (q != null) {
+        if (q != null && queued) {
             q.thread = null;
-            if (q.interrupted) {
-                if (interruptible)
-                    cleanStack();
-                else
-                    Thread.currentThread().interrupt();
-            }
+            if (!interruptible && q.interrupted)
+                Thread.currentThread().interrupt();
+            if (r == null)
+                cleanStack();
         }
-        if (r != null)
+        if (r != null || (r = result) != null)
             postComplete();
         return r;
     }
@@ -1808,9 +1853,12 @@
             Signaller q = null;
             boolean queued = false;
             Object r;
-            while ((r = result) == null) { // similar to untimed, without spins
-                if (q == null)
+            while ((r = result) == null) { // similar to untimed
+                if (q == null) {
                     q = new Signaller(true, nanos, deadline);
+                    if (Thread.currentThread() instanceof ForkJoinWorkerThread)
+                        ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
+                }
                 else if (!queued)
                     queued = tryPushStack(q);
                 else if (q.nanos <= 0L)
@@ -1825,12 +1873,13 @@
                         break;
                 }
             }
-            if (q != null)
+            if (q != null && queued) {
                 q.thread = null;
-            if (r != null)
+                if (r == null)
+                    cleanStack();
+            }
+            if (r != null || (r = result) != null)
                 postComplete();
-            else
-                cleanStack();
             if (r != null || (q != null && q.interrupted))
                 return r;
         }
@@ -1942,9 +1991,12 @@
      * @throws InterruptedException if the current thread was interrupted
      * while waiting
      */
+    @SuppressWarnings("unchecked")
     public T get() throws InterruptedException, ExecutionException {
         Object r;
-        return reportGet((r = result) == null ? waitingGet(true) : r);
+        if ((r = result) == null)
+            r = waitingGet(true);
+        return (T) reportGet(r);
     }
 
     /**
@@ -1960,11 +2012,14 @@
      * while waiting
      * @throws TimeoutException if the wait timed out
      */
+    @SuppressWarnings("unchecked")
     public T get(long timeout, TimeUnit unit)
         throws InterruptedException, ExecutionException, TimeoutException {
+        long nanos = unit.toNanos(timeout);
         Object r;
-        long nanos = unit.toNanos(timeout);
-        return reportGet((r = result) == null ? timedGet(nanos) : r);
+        if ((r = result) == null)
+            r = timedGet(nanos);
+        return (T) reportGet(r);
     }
 
     /**
@@ -1981,9 +2036,12 @@
      * @throws CompletionException if this future completed
      * exceptionally or a completion computation threw an exception
      */
+    @SuppressWarnings("unchecked")
     public T join() {
         Object r;
-        return reportJoin((r = result) == null ? waitingGet(false) : r);
+        if ((r = result) == null)
+            r = waitingGet(false);
+        return (T) reportJoin(r);
     }
 
     /**
@@ -1996,9 +2054,10 @@
      * @throws CompletionException if this future completed
      * exceptionally or a completion computation threw an exception
      */
+    @SuppressWarnings("unchecked")
     public T getNow(T valueIfAbsent) {
         Object r;
-        return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
+        return ((r = result) == null) ? valueIfAbsent : (T) reportJoin(r);
     }
 
     /**
@@ -2294,7 +2353,28 @@
      * {@code null}
      */
     public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
-        return orTree(cfs, 0, cfs.length - 1);
+        int n; Object r;
+        if ((n = cfs.length) <= 1)
+            return (n == 0)
+                ? new CompletableFuture<Object>()
+                : uniCopyStage(cfs[0]);
+        for (CompletableFuture<?> cf : cfs)
+            if ((r = cf.result) != null)
+                return new CompletableFuture<Object>(encodeRelay(r));
+        cfs = cfs.clone();
+        CompletableFuture<Object> d = new CompletableFuture<>();
+        for (CompletableFuture<?> cf : cfs)
+            cf.unipush(new AnyOf(d, cf, cfs));
+        // If d was completed while we were adding completions, we should
+        // clean the stack of any sources that may have had completions
+        // pushed on their stack after d was completed.
+        if (d.result != null)
+            for (int i = 0, len = cfs.length; i < len; i++)
+                if (cfs[i].result != null)
+                    for (i++; i < len; i++)
+                        if (cfs[i].result == null)
+                            cfs[i].cleanStack();
+        return d;
     }
 
     /* ------------- Control and status methods -------------- */
@@ -2466,7 +2546,7 @@
      * @since 9
      */
     public CompletableFuture<T> copy() {
-        return uniCopyStage();
+        return uniCopyStage(this);
     }
 
     /**
@@ -2775,19 +2855,16 @@
             throw new UnsupportedOperationException(); }
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long RESULT;
-    private static final long STACK;
-    private static final long NEXT;
+    // VarHandle mechanics
+    private static final VarHandle RESULT;
+    private static final VarHandle STACK;
+    private static final VarHandle NEXT;
     static {
         try {
-            RESULT = U.objectFieldOffset
-                (CompletableFuture.class.getDeclaredField("result"));
-            STACK = U.objectFieldOffset
-                (CompletableFuture.class.getDeclaredField("stack"));
-            NEXT = U.objectFieldOffset
-                (Completion.class.getDeclaredField("next"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            RESULT = l.findVarHandle(CompletableFuture.class, "result", Object.class);
+            STACK = l.findVarHandle(CompletableFuture.class, "stack", Completion.class);
+            NEXT = l.findVarHandle(Completion.class, "next", Completion.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Wed Jul 05 22:00:06 2017 +0200
@@ -68,6 +68,7 @@
 import java.util.function.ToLongBiFunction;
 import java.util.function.ToLongFunction;
 import java.util.stream.Stream;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A hash table supporting full concurrency of retrievals and
@@ -747,7 +748,7 @@
     /* ---------------- Table element access -------------- */
 
     /*
-     * Volatile access methods are used for table elements as well as
+     * Atomic access methods are used for table elements as well as
      * elements of in-progress next table while resizing.  All uses of
      * the tab arguments must be null checked by callers.  All callers
      * also paranoically precheck that tab's length is not zero (or an
@@ -757,14 +758,12 @@
      * errors by users, these checks must operate on local variables,
      * which accounts for some odd-looking inline assignments below.
      * Note that calls to setTabAt always occur within locked regions,
-     * and so in principle require only release ordering, not
-     * full volatile semantics, but are currently coded as volatile
-     * writes to be conservative.
+     * and so require only release ordering.
      */
 
     @SuppressWarnings("unchecked")
     static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
-        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+        return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
     }
 
     static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
@@ -773,7 +772,7 @@
     }
 
     static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
-        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+        U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
     }
 
     /* ---------------- Fields -------------- */
@@ -1024,7 +1023,7 @@
         int hash = spread(key.hashCode());
         int binCount = 0;
         for (Node<K,V>[] tab = table;;) {
-            Node<K,V> f; int n, i, fh;
+            Node<K,V> f; int n, i, fh; K fk; V fv;
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
@@ -1033,6 +1032,10 @@
             }
             else if ((fh = f.hash) == MOVED)
                 tab = helpTransfer(tab, f);
+            else if (onlyIfAbsent && fh == hash &&  // check first node
+                     ((fk = f.key) == key || fk != null && key.equals(fk)) &&
+                     (fv = f.val) != null)
+                return fv;
             else {
                 V oldVal = null;
                 synchronized (f) {
@@ -1703,7 +1706,7 @@
         V val = null;
         int binCount = 0;
         for (Node<K,V>[] tab = table;;) {
-            Node<K,V> f; int n, i, fh;
+            Node<K,V> f; int n, i, fh; K fk; V fv;
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
@@ -1725,6 +1728,10 @@
             }
             else if ((fh = f.hash) == MOVED)
                 tab = helpTransfer(tab, f);
+            else if (fh == h &&                  // check first node
+                     ((fk = f.key) == key || fk != null && key.equals(fk)) &&
+                     (fv = f.val) != null)
+                return fv;
             else {
                 boolean added = false;
                 synchronized (f) {
@@ -3298,7 +3305,7 @@
             return true;
         }
 
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+        private static final Unsafe U = Unsafe.getUnsafe();
         private static final long LOCKSTATE;
         static {
             try {
@@ -4554,14 +4561,21 @@
             return true;
         }
 
-        public final boolean removeAll(Collection<?> c) {
+        public boolean removeAll(Collection<?> c) {
             if (c == null) throw new NullPointerException();
             boolean modified = false;
-            for (Iterator<E> it = iterator(); it.hasNext();) {
-                if (c.contains(it.next())) {
-                    it.remove();
-                    modified = true;
+            // Use (c instanceof Set) as a hint that lookup in c is as
+            // efficient as this view
+            if (c instanceof Set<?> && c.size() > map.table.length) {
+                for (Iterator<?> it = iterator(); it.hasNext(); ) {
+                    if (c.contains(it.next())) {
+                        it.remove();
+                        modified = true;
+                    }
                 }
+            } else {
+                for (Object e : c)
+                    modified |= remove(e);
             }
             return modified;
         }
@@ -4748,6 +4762,18 @@
             throw new UnsupportedOperationException();
         }
 
+        @Override public boolean removeAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            for (Iterator<V> it = iterator(); it.hasNext();) {
+                if (c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
         public boolean removeIf(Predicate<? super V> filter) {
             return map.removeValueIf(filter);
         }
@@ -6341,7 +6367,7 @@
     }
 
     // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+    private static final Unsafe U = Unsafe.getUnsafe();
     private static final long SIZECTL;
     private static final long TRANSFERINDEX;
     private static final long BASECOUNT;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractCollection;
 import java.util.Arrays;
 import java.util.Collection;
@@ -292,64 +294,23 @@
         volatile Node<E> prev;
         volatile E item;
         volatile Node<E> next;
-
-        Node() {  // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
-        }
-
-        /**
-         * Constructs a new node.  Uses relaxed write because item can
-         * only be seen after publication via casNext or casPrev.
-         */
-        Node(E item) {
-            U.putObject(this, ITEM, item);
-        }
-
-        boolean casItem(E cmp, E val) {
-            return U.compareAndSwapObject(this, ITEM, cmp, val);
-        }
-
-        void lazySetNext(Node<E> val) {
-            U.putObjectRelease(this, NEXT, val);
-        }
-
-        boolean casNext(Node<E> cmp, Node<E> val) {
-            return U.compareAndSwapObject(this, NEXT, cmp, val);
-        }
+    }
 
-        void lazySetPrev(Node<E> val) {
-            U.putObjectRelease(this, PREV, val);
-        }
-
-        boolean casPrev(Node<E> cmp, Node<E> val) {
-            return U.compareAndSwapObject(this, PREV, cmp, val);
-        }
-
-        // Unsafe mechanics
-
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long PREV;
-        private static final long ITEM;
-        private static final long NEXT;
-
-        static {
-            try {
-                PREV = U.objectFieldOffset
-                    (Node.class.getDeclaredField("prev"));
-                ITEM = U.objectFieldOffset
-                    (Node.class.getDeclaredField("item"));
-                NEXT = U.objectFieldOffset
-                    (Node.class.getDeclaredField("next"));
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-        }
+    /**
+     * Returns a new node holding item.  Uses relaxed write because item
+     * can only be seen after piggy-backing publication via CAS.
+     */
+    static <E> Node<E> newNode(E item) {
+        Node<E> node = new Node<E>();
+        ITEM.set(node, item);
+        return node;
     }
 
     /**
      * Links e as first element.
      */
     private void linkFirst(E e) {
-        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
 
         restartFromHead:
         for (;;)
@@ -363,13 +324,13 @@
                     continue restartFromHead;
                 else {
                     // p is first node
-                    newNode.lazySetNext(p); // CAS piggyback
-                    if (p.casPrev(null, newNode)) {
+                    NEXT.set(newNode, p); // CAS piggyback
+                    if (PREV.compareAndSet(p, null, newNode)) {
                         // Successful CAS is the linearization point
                         // for e to become an element of this deque,
                         // and for newNode to become "live".
-                        if (p != h) // hop two nodes at a time
-                            casHead(h, newNode);  // Failure is OK.
+                        if (p != h) // hop two nodes at a time; failure is OK
+                            HEAD.weakCompareAndSetVolatile(this, h, newNode);
                         return;
                     }
                     // Lost CAS race to another thread; re-read prev
@@ -381,7 +342,7 @@
      * Links e as last element.
      */
     private void linkLast(E e) {
-        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
 
         restartFromTail:
         for (;;)
@@ -395,13 +356,13 @@
                     continue restartFromTail;
                 else {
                     // p is last node
-                    newNode.lazySetPrev(p); // CAS piggyback
-                    if (p.casNext(null, newNode)) {
+                    PREV.set(newNode, p); // CAS piggyback
+                    if (NEXT.compareAndSet(p, null, newNode)) {
                         // Successful CAS is the linearization point
                         // for e to become an element of this deque,
                         // and for newNode to become "live".
-                        if (p != t) // hop two nodes at a time
-                            casTail(t, newNode);  // Failure is OK.
+                        if (p != t) // hop two nodes at a time; failure is OK
+                            TAIL.weakCompareAndSetVolatile(this, t, newNode);
                         return;
                     }
                     // Lost CAS race to another thread; re-read next
@@ -516,8 +477,8 @@
                 updateTail(); // Ensure x is not reachable from tail
 
                 // Finally, actually gc-unlink
-                x.lazySetPrev(isFirst ? prevTerminator() : x);
-                x.lazySetNext(isLast  ? nextTerminator() : x);
+                PREV.setRelease(x, isFirst ? prevTerminator() : x);
+                NEXT.setRelease(x, isLast  ? nextTerminator() : x);
             }
         }
     }
@@ -531,7 +492,8 @@
         // assert first.item == null;
         for (Node<E> o = null, p = next, q;;) {
             if (p.item != null || (q = p.next) == null) {
-                if (o != null && p.prev != p && first.casNext(next, p)) {
+                if (o != null && p.prev != p &&
+                    NEXT.compareAndSet(first, next, p)) {
                     skipDeletedPredecessors(p);
                     if (first.prev == null &&
                         (p.next == null || p.item != null) &&
@@ -541,8 +503,8 @@
                         updateTail(); // Ensure o is not reachable from tail
 
                         // Finally, actually gc-unlink
-                        o.lazySetNext(o);
-                        o.lazySetPrev(prevTerminator());
+                        NEXT.setRelease(o, o);
+                        PREV.setRelease(o, prevTerminator());
                     }
                 }
                 return;
@@ -565,7 +527,8 @@
         // assert last.item == null;
         for (Node<E> o = null, p = prev, q;;) {
             if (p.item != null || (q = p.prev) == null) {
-                if (o != null && p.next != p && last.casPrev(prev, p)) {
+                if (o != null && p.next != p &&
+                    PREV.compareAndSet(last, prev, p)) {
                     skipDeletedSuccessors(p);
                     if (last.next == null &&
                         (p.prev == null || p.item != null) &&
@@ -575,8 +538,8 @@
                         updateTail(); // Ensure o is not reachable from tail
 
                         // Finally, actually gc-unlink
-                        o.lazySetPrev(o);
-                        o.lazySetNext(nextTerminator());
+                        PREV.setRelease(o, o);
+                        NEXT.setRelease(o, nextTerminator());
                     }
                 }
                 return;
@@ -607,7 +570,7 @@
                     (q = (p = q).prev) == null) {
                     // It is possible that p is PREV_TERMINATOR,
                     // but if so, the CAS is guaranteed to fail.
-                    if (casHead(h, p))
+                    if (HEAD.compareAndSet(this, h, p))
                         return;
                     else
                         continue restartFromHead;
@@ -637,7 +600,7 @@
                     (q = (p = q).next) == null) {
                     // It is possible that p is NEXT_TERMINATOR,
                     // but if so, the CAS is guaranteed to fail.
-                    if (casTail(t, p))
+                    if (TAIL.compareAndSet(this, t, p))
                         return;
                     else
                         continue restartFromTail;
@@ -675,7 +638,7 @@
             }
 
             // found active CAS target
-            if (prev == p || x.casPrev(prev, p))
+            if (prev == p || PREV.compareAndSet(x, prev, p))
                 return;
 
         } while (x.item != null || x.next == null);
@@ -706,7 +669,7 @@
             }
 
             // found active CAS target
-            if (next == p || x.casNext(next, p))
+            if (next == p || NEXT.compareAndSet(x, next, p))
                 return;
 
         } while (x.item != null || x.prev == null);
@@ -751,7 +714,7 @@
                 else if (p == h
                          // It is possible that p is PREV_TERMINATOR,
                          // but if so, the CAS is guaranteed to fail.
-                         || casHead(h, p))
+                         || HEAD.compareAndSet(this, h, p))
                     return p;
                 else
                     continue restartFromHead;
@@ -776,7 +739,7 @@
                 else if (p == t
                          // It is possible that p is NEXT_TERMINATOR,
                          // but if so, the CAS is guaranteed to fail.
-                         || casTail(t, p))
+                         || TAIL.compareAndSet(this, t, p))
                     return p;
                 else
                     continue restartFromTail;
@@ -802,7 +765,7 @@
      * Constructs an empty deque.
      */
     public ConcurrentLinkedDeque() {
-        head = tail = new Node<E>(null);
+        head = tail = new Node<E>();
     }
 
     /**
@@ -818,12 +781,12 @@
         // Copy c into a private chain of Nodes
         Node<E> h = null, t = null;
         for (E e : c) {
-            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
             if (h == null)
                 h = t = newNode;
             else {
-                t.lazySetNext(newNode);
-                newNode.lazySetPrev(t);
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
                 t = newNode;
             }
         }
@@ -836,12 +799,12 @@
     private void initHeadTail(Node<E> h, Node<E> t) {
         if (h == t) {
             if (h == null)
-                h = t = new Node<E>(null);
+                h = t = new Node<E>();
             else {
                 // Avoid edge case of a single Node with non-null item.
-                Node<E> newNode = new Node<E>(null);
-                t.lazySetNext(newNode);
-                newNode.lazySetPrev(t);
+                Node<E> newNode = new Node<E>();
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
                 t = newNode;
             }
         }
@@ -934,7 +897,7 @@
     public E pollFirst() {
         for (Node<E> p = first(); p != null; p = succ(p)) {
             E item = p.item;
-            if (item != null && p.casItem(item, null)) {
+            if (item != null && ITEM.compareAndSet(p, item, null)) {
                 unlink(p);
                 return item;
             }
@@ -945,7 +908,7 @@
     public E pollLast() {
         for (Node<E> p = last(); p != null; p = pred(p)) {
             E item = p.item;
-            if (item != null && p.casItem(item, null)) {
+            if (item != null && ITEM.compareAndSet(p, item, null)) {
                 unlink(p);
                 return item;
             }
@@ -1031,7 +994,8 @@
         Objects.requireNonNull(o);
         for (Node<E> p = first(); p != null; p = succ(p)) {
             E item = p.item;
-            if (item != null && o.equals(item) && p.casItem(item, null)) {
+            if (item != null && o.equals(item) &&
+                ITEM.compareAndSet(p, item, null)) {
                 unlink(p);
                 return true;
             }
@@ -1055,7 +1019,8 @@
         Objects.requireNonNull(o);
         for (Node<E> p = last(); p != null; p = pred(p)) {
             E item = p.item;
-            if (item != null && o.equals(item) && p.casItem(item, null)) {
+            if (item != null && o.equals(item) &&
+                ITEM.compareAndSet(p, item, null)) {
                 unlink(p);
                 return true;
             }
@@ -1159,12 +1124,12 @@
         // Copy c into a private chain of Nodes
         Node<E> beginningOfTheEnd = null, last = null;
         for (E e : c) {
-            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
             if (beginningOfTheEnd == null)
                 beginningOfTheEnd = last = newNode;
             else {
-                last.lazySetNext(newNode);
-                newNode.lazySetPrev(last);
+                NEXT.set(last, newNode);
+                PREV.set(newNode, last);
                 last = newNode;
             }
         }
@@ -1184,16 +1149,16 @@
                     continue restartFromTail;
                 else {
                     // p is last node
-                    beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
-                    if (p.casNext(null, beginningOfTheEnd)) {
+                    PREV.set(beginningOfTheEnd, p); // CAS piggyback
+                    if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
                         // Successful CAS is the linearization point
                         // for all elements to be added to this deque.
-                        if (!casTail(t, last)) {
+                        if (!TAIL.weakCompareAndSetVolatile(this, t, last)) {
                             // Try a little harder to update tail,
                             // since we may be adding many elements.
                             t = tail;
                             if (last.next == null)
-                                casTail(t, last);
+                                TAIL.weakCompareAndSetVolatile(this, t, last);
                         }
                         return true;
                     }
@@ -1586,41 +1551,38 @@
         Node<E> h = null, t = null;
         for (Object item; (item = s.readObject()) != null; ) {
             @SuppressWarnings("unchecked")
-            Node<E> newNode = new Node<E>((E) item);
+            Node<E> newNode = newNode((E) item);
             if (h == null)
                 h = t = newNode;
             else {
-                t.lazySetNext(newNode);
-                newNode.lazySetPrev(t);
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
                 t = newNode;
             }
         }
         initHeadTail(h, t);
     }
 
-    private boolean casHead(Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(this, HEAD, cmp, val);
-    }
-
-    private boolean casTail(Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(this, TAIL, cmp, val);
-    }
-
-    // Unsafe mechanics
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long HEAD;
-    private static final long TAIL;
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    private static final VarHandle PREV;
+    private static final VarHandle NEXT;
+    private static final VarHandle ITEM;
     static {
         PREV_TERMINATOR = new Node<Object>();
         PREV_TERMINATOR.next = PREV_TERMINATOR;
         NEXT_TERMINATOR = new Node<Object>();
         NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
         try {
-            HEAD = U.objectFieldOffset
-                (ConcurrentLinkedDeque.class.getDeclaredField("head"));
-            TAIL = U.objectFieldOffset
-                (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentLinkedDeque.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(ConcurrentLinkedDeque.class, "tail",
+                                   Node.class);
+            PREV = l.findVarHandle(Node.class, "prev", Node.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            ITEM = l.findVarHandle(Node.class, "item", Object.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
@@ -166,9 +168,8 @@
      * this is merely an optimization.
      *
      * When constructing a Node (before enqueuing it) we avoid paying
-     * for a volatile write to item by using Unsafe.putObject instead
-     * of a normal write.  This allows the cost of enqueue to be
-     * "one-and-a-half" CASes.
+     * for a volatile write to item.  This allows the cost of enqueue
+     * to be "one-and-a-half" CASes.
      *
      * Both head and tail may or may not point to a Node with a
      * non-null item.  If the queue is empty, all items must of course
@@ -178,33 +179,21 @@
      * optimization.
      */
 
-    private static class Node<E> {
+    static final class Node<E> {
         volatile E item;
         volatile Node<E> next;
     }
 
     /**
      * Returns a new node holding item.  Uses relaxed write because item
-     * can only be seen after piggy-backing publication via casNext.
+     * can only be seen after piggy-backing publication via CAS.
      */
     static <E> Node<E> newNode(E item) {
         Node<E> node = new Node<E>();
-        U.putObject(node, ITEM, item);
+        ITEM.set(node, item);
         return node;
     }
 
-    static <E> boolean casItem(Node<E> node, E cmp, E val) {
-        return U.compareAndSwapObject(node, ITEM, cmp, val);
-    }
-
-    static <E> void lazySetNext(Node<E> node, Node<E> val) {
-        U.putObjectRelease(node, NEXT, val);
-    }
-
-    static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(node, NEXT, cmp, val);
-    }
-
     /**
      * A node from which the first live (non-deleted) node (if any)
      * can be reached in O(1) time.
@@ -256,7 +245,7 @@
             if (h == null)
                 h = t = newNode;
             else {
-                lazySetNext(t, newNode);
+                NEXT.set(t, newNode);
                 t = newNode;
             }
         }
@@ -286,8 +275,8 @@
      */
     final void updateHead(Node<E> h, Node<E> p) {
         // assert h != null && p != null && (h == p || h.item == null);
-        if (h != p && casHead(h, p))
-            lazySetNext(h, h);
+        if (h != p && HEAD.compareAndSet(this, h, p))
+            NEXT.setRelease(h, h);
     }
 
     /**
@@ -314,12 +303,12 @@
             Node<E> q = p.next;
             if (q == null) {
                 // p is last node
-                if (casNext(p, null, newNode)) {
+                if (NEXT.compareAndSet(p, null, newNode)) {
                     // Successful CAS is the linearization point
                     // for e to become an element of this queue,
                     // and for newNode to become "live".
-                    if (p != t) // hop two nodes at a time
-                        casTail(t, newNode);  // Failure is OK.
+                    if (p != t) // hop two nodes at a time; failure is OK
+                        TAIL.weakCompareAndSetVolatile(this, t, newNode);
                     return true;
                 }
                 // Lost CAS race to another thread; re-read next
@@ -342,7 +331,7 @@
             for (Node<E> h = head, p = h, q;;) {
                 E item = p.item;
 
-                if (item != null && casItem(p, item, null)) {
+                if (item != null && ITEM.compareAndSet(p, item, null)) {
                     // Successful CAS is the linearization point
                     // for item to be removed from this queue.
                     if (p != h) // hop two nodes at a time
@@ -483,12 +472,12 @@
                         next = succ(p);
                         continue;
                     }
-                    removed = casItem(p, item, null);
+                    removed = ITEM.compareAndSet(p, item, null);
                 }
 
                 next = succ(p);
                 if (pred != null && next != null) // unlink
-                    casNext(pred, p, next);
+                    NEXT.weakCompareAndSetVolatile(pred, p, next);
                 if (removed)
                     return true;
             }
@@ -520,7 +509,7 @@
             if (beginningOfTheEnd == null)
                 beginningOfTheEnd = last = newNode;
             else {
-                lazySetNext(last, newNode);
+                NEXT.set(last, newNode);
                 last = newNode;
             }
         }
@@ -532,15 +521,15 @@
             Node<E> q = p.next;
             if (q == null) {
                 // p is last node
-                if (casNext(p, null, beginningOfTheEnd)) {
+                if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
                     // Successful CAS is the linearization point
                     // for all elements to be added to this queue.
-                    if (!casTail(t, last)) {
+                    if (!TAIL.weakCompareAndSetVolatile(this, t, last)) {
                         // Try a little harder to update tail,
                         // since we may be adding many elements.
                         t = tail;
                         if (last.next == null)
-                            casTail(t, last);
+                            TAIL.weakCompareAndSetVolatile(this, t, last);
                     }
                     return true;
                 }
@@ -744,7 +733,7 @@
                 }
                 // unlink deleted nodes
                 if ((q = succ(p)) != null)
-                    casNext(pred, p, q);
+                    NEXT.compareAndSet(pred, p, q);
             }
         }
 
@@ -801,7 +790,7 @@
             if (h == null)
                 h = t = newNode;
             else {
-                lazySetNext(t, newNode);
+                NEXT.set(t, newNode);
                 t = newNode;
             }
         }
@@ -919,31 +908,20 @@
         return new CLQSpliterator<E>(this);
     }
 
-    private boolean casTail(Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(this, TAIL, cmp, val);
-    }
-
-    private boolean casHead(Node<E> cmp, Node<E> val) {
-        return U.compareAndSwapObject(this, HEAD, cmp, val);
-    }
-
-    // Unsafe mechanics
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long HEAD;
-    private static final long TAIL;
-    private static final long ITEM;
-    private static final long NEXT;
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    private static final VarHandle ITEM;
+    private static final VarHandle NEXT;
     static {
         try {
-            HEAD = U.objectFieldOffset
-                (ConcurrentLinkedQueue.class.getDeclaredField("head"));
-            TAIL = U.objectFieldOffset
-                (ConcurrentLinkedQueue.class.getDeclaredField("tail"));
-            ITEM = U.objectFieldOffset
-                (Node.class.getDeclaredField("item"));
-            NEXT = U.objectFieldOffset
-                (Node.class.getDeclaredField("next"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentLinkedQueue.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(ConcurrentLinkedQueue.class, "tail",
+                                   Node.class);
+            ITEM = l.findVarHandle(Node.class, "item", Object.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.io.Serializable;
 import java.util.AbstractCollection;
 import java.util.AbstractMap;
@@ -401,7 +403,7 @@
      * compareAndSet head node.
      */
     private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
-        return U.compareAndSwapObject(this, HEAD, cmp, val);
+        return HEAD.compareAndSet(this, cmp, val);
     }
 
     /* ---------------- Nodes -------------- */
@@ -444,14 +446,14 @@
          * compareAndSet value field.
          */
         boolean casValue(Object cmp, Object val) {
-            return U.compareAndSwapObject(this, VALUE, cmp, val);
+            return VALUE.compareAndSet(this, cmp, val);
         }
 
         /**
          * compareAndSet next field.
          */
         boolean casNext(Node<K,V> cmp, Node<K,V> val) {
-            return U.compareAndSwapObject(this, NEXT, cmp, val);
+            return NEXT.compareAndSet(this, cmp, val);
         }
 
         /**
@@ -532,20 +534,16 @@
             return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
         }
 
-        // Unsafe mechanics
-
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long VALUE;
-        private static final long NEXT;
-
+        // VarHandle mechanics
+        private static final VarHandle VALUE;
+        private static final VarHandle NEXT;
         static {
             try {
-                VALUE = U.objectFieldOffset
-                    (Node.class.getDeclaredField("value"));
-                NEXT = U.objectFieldOffset
-                    (Node.class.getDeclaredField("next"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                VALUE = l.findVarHandle(Node.class, "value", Object.class);
+                NEXT = l.findVarHandle(Node.class, "next", Node.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                    throw new Error(e);
             }
         }
     }
@@ -577,7 +575,7 @@
          * compareAndSet right field.
          */
         final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
-            return U.compareAndSwapObject(this, RIGHT, cmp, val);
+            return RIGHT.compareAndSet(this, cmp, val);
         }
 
         /**
@@ -613,13 +611,12 @@
             return node.value != null && casRight(succ, succ.right);
         }
 
-        // Unsafe mechanics
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long RIGHT;
+        // VarHandle mechanics
+        private static final VarHandle RIGHT;
         static {
             try {
-                RIGHT = U.objectFieldOffset
-                    (Index.class.getDeclaredField("right"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                RIGHT = l.findVarHandle(Index.class, "right", Index.class);
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
@@ -3607,13 +3604,13 @@
         }
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long HEAD;
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
     static {
         try {
-            HEAD = U.objectFieldOffset
-                (ConcurrentSkipListMap.class.getDeclaredField("head"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
+                                   HeadIndex.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractSet;
 import java.util.Collection;
 import java.util.Collections;
@@ -507,15 +509,16 @@
 
     // Support for resetting map in clone
     private void setMap(ConcurrentNavigableMap<E,Object> map) {
-        U.putObjectVolatile(this, MAP, map);
+        MAP.setVolatile(this, map);
     }
 
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long MAP;
+    // VarHandle mechanics
+    private static final VarHandle MAP;
     static {
         try {
-            MAP = U.objectFieldOffset
-                (ConcurrentSkipListSet.class.getDeclaredField("m"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            MAP = l.findVarHandle(ConcurrentSkipListSet.class, "m",
+                                  ConcurrentNavigableMap.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Wed Jul 05 22:00:06 2017 +0200
@@ -34,6 +34,7 @@
 
 package java.util.concurrent;
 
+import java.lang.reflect.Field;
 import java.util.AbstractList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -1541,17 +1542,21 @@
         }
     }
 
-    // Support for resetting lock while deserializing
+    /** Initializes the lock; for use when deserializing or cloning. */
     private void resetLock() {
-        U.putObjectVolatile(this, LOCK, new Object());
-    }
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long LOCK;
-    static {
+        Field lockField = java.security.AccessController.doPrivileged(
+            (java.security.PrivilegedAction<Field>) () -> {
+                try {
+                    Field f = CopyOnWriteArrayList.class
+                        .getDeclaredField("lock");
+                    f.setAccessible(true);
+                    return f;
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }});
         try {
-            LOCK = U.objectFieldOffset
-                (CopyOnWriteArrayList.class.getDeclaredField("lock"));
-        } catch (ReflectiveOperationException e) {
+            lockField.set(this, new Object());
+        } catch (IllegalAccessException e) {
             throw new Error(e);
         }
     }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,9 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
 /**
  * A {@link ForkJoinTask} with a completion action performed when
  * triggered and there are no remaining pending actions.
@@ -524,7 +527,7 @@
      * @param delta the value to add
      */
     public final void addToPendingCount(int delta) {
-        U.getAndAddInt(this, PENDING, delta);
+        PENDING.getAndAdd(this, delta);
     }
 
     /**
@@ -536,7 +539,7 @@
      * @return {@code true} if successful
      */
     public final boolean compareAndSetPendingCount(int expected, int count) {
-        return U.compareAndSwapInt(this, PENDING, expected, count);
+        return PENDING.compareAndSet(this, expected, count);
     }
 
     /**
@@ -548,7 +551,7 @@
     public final int decrementPendingCountUnlessZero() {
         int c;
         do {} while ((c = pending) != 0 &&
-                     !U.compareAndSwapInt(this, PENDING, c, c - 1));
+                     !PENDING.weakCompareAndSetVolatile(this, c, c - 1));
         return c;
     }
 
@@ -581,7 +584,7 @@
                     return;
                 }
             }
-            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+            else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
                 return;
         }
     }
@@ -604,7 +607,7 @@
                     return;
                 }
             }
-            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+            else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
                 return;
         }
     }
@@ -649,7 +652,7 @@
         for (int c;;) {
             if ((c = pending) == 0)
                 return this;
-            else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
+            else if (PENDING.weakCompareAndSetVolatile(this, c, c - 1))
                 return null;
         }
     }
@@ -753,13 +756,13 @@
      */
     protected void setRawResult(T t) { }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long PENDING;
+    // VarHandle mechanics
+    private static final VarHandle PENDING;
     static {
         try {
-            PENDING = U.objectFieldOffset
-                (CountedCompleter.class.getDeclaredField("pending"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
+
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java	Wed Jul 05 22:00:06 2017 +0200
@@ -36,6 +36,10 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.locks.LockSupport;
+
 /**
  * A synchronization point at which threads can pair and swap elements
  * within pairs.  Each thread presents some object on entry to the
@@ -155,9 +159,7 @@
      * a value that is enough for common platforms.  Additionally,
      * extra care elsewhere is taken to avoid other false/unintended
      * sharing and to enhance locality, including adding padding (via
-     * @Contended) to Nodes, embedding "bound" as an Exchanger field,
-     * and reworking some park/unpark mechanics compared to
-     * LockSupport versions.
+     * @Contended) to Nodes, embedding "bound" as an Exchanger field.
      *
      * The arena starts out with only one used slot. We expand the
      * effective arena size by tracking collisions; i.e., failed CASes
@@ -233,29 +235,23 @@
      * As is too common in this sort of code, methods are monolithic
      * because most of the logic relies on reads of fields that are
      * maintained as local variables so can't be nicely factored --
-     * mainly, here, bulky spin->yield->block/cancel code), and
-     * heavily dependent on intrinsics (Unsafe) to use inlined
-     * embedded CAS and related memory access operations (that tend
-     * not to be as readily inlined by dynamic compilers when they are
-     * hidden behind other methods that would more nicely name and
-     * encapsulate the intended effects). This includes the use of
-     * putXRelease to clear fields of the per-thread Nodes between
-     * uses. Note that field Node.item is not declared as volatile
-     * even though it is read by releasing threads, because they only
-     * do so after CAS operations that must precede access, and all
-     * uses by the owning thread are otherwise acceptably ordered by
-     * other operations. (Because the actual points of atomicity are
-     * slot CASes, it would also be legal for the write to Node.match
-     * in a release to be weaker than a full volatile write. However,
-     * this is not done because it could allow further postponement of
-     * the write, delaying progress.)
+     * mainly, here, bulky spin->yield->block/cancel code.  Note that
+     * field Node.item is not declared as volatile even though it is
+     * read by releasing threads, because they only do so after CAS
+     * operations that must precede access, and all uses by the owning
+     * thread are otherwise acceptably ordered by other operations.
+     * (Because the actual points of atomicity are slot CASes, it
+     * would also be legal for the write to Node.match in a release to
+     * be weaker than a full volatile write. However, this is not done
+     * because it could allow further postponement of the write,
+     * delaying progress.)
      */
 
     /**
-     * The byte distance (as a shift value) between any two used slots
-     * in the arena.  1 << ASHIFT should be at least cacheline size.
+     * The index distance (as a shift value) between any two used slots
+     * in the arena, spacing them out to avoid false sharing.
      */
-    private static final int ASHIFT = 7;
+    private static final int ASHIFT = 5;
 
     /**
      * The maximum supported arena index. The maximum allocatable
@@ -356,27 +352,31 @@
      */
     private final Object arenaExchange(Object item, boolean timed, long ns) {
         Node[] a = arena;
+        int alen = a.length;
         Node p = participant.get();
         for (int i = p.index;;) {                      // access slot at i
-            int b, m, c; long j;                       // j is raw array offset
-            Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
-            if (q != null && U.compareAndSwapObject(a, j, q, null)) {
+            int b, m, c;
+            int j = (i << ASHIFT) + ((1 << ASHIFT) - 1);
+            if (j < 0 || j >= alen)
+                j = alen - 1;
+            Node q = (Node)AA.getAcquire(a, j);
+            if (q != null && AA.compareAndSet(a, j, q, null)) {
                 Object v = q.item;                     // release
                 q.match = item;
                 Thread w = q.parked;
                 if (w != null)
-                    U.unpark(w);
+                    LockSupport.unpark(w);
                 return v;
             }
             else if (i <= (m = (b = bound) & MMASK) && q == null) {
                 p.item = item;                         // offer
-                if (U.compareAndSwapObject(a, j, null, p)) {
+                if (AA.compareAndSet(a, j, null, p)) {
                     long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
                     Thread t = Thread.currentThread(); // wait
                     for (int h = p.hash, spins = SPINS;;) {
                         Object v = p.match;
                         if (v != null) {
-                            U.putObjectRelease(p, MATCH, null);
+                            MATCH.setRelease(p, null);
                             p.item = null;             // clear for next use
                             p.hash = h;
                             return v;
@@ -389,22 +389,24 @@
                                      (--spins & ((SPINS >>> 1) - 1)) == 0)
                                 Thread.yield();        // two yields per wait
                         }
-                        else if (U.getObjectVolatile(a, j) != p)
+                        else if (AA.getAcquire(a, j) != p)
                             spins = SPINS;       // releaser hasn't set match yet
                         else if (!t.isInterrupted() && m == 0 &&
                                  (!timed ||
                                   (ns = end - System.nanoTime()) > 0L)) {
-                            U.putObject(t, BLOCKER, this); // emulate LockSupport
                             p.parked = t;              // minimize window
-                            if (U.getObjectVolatile(a, j) == p)
-                                U.park(false, ns);
+                            if (AA.getAcquire(a, j) == p) {
+                                if (ns == 0L)
+                                    LockSupport.park(this);
+                                else
+                                    LockSupport.parkNanos(this, ns);
+                            }
                             p.parked = null;
-                            U.putObject(t, BLOCKER, null);
                         }
-                        else if (U.getObjectVolatile(a, j) == p &&
-                                 U.compareAndSwapObject(a, j, p, null)) {
+                        else if (AA.getAcquire(a, j) == p &&
+                                 AA.compareAndSet(a, j, p, null)) {
                             if (m != 0)                // try to shrink
-                                U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
+                                BOUND.compareAndSet(this, b, b + SEQ - 1);
                             p.item = null;
                             p.hash = h;
                             i = p.index >>>= 1;        // descend
@@ -426,7 +428,7 @@
                     i = (i != m || m == 0) ? m : m - 1;
                 }
                 else if ((c = p.collides) < m || m == FULL ||
-                         !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
+                         !BOUND.compareAndSet(this, b, b + SEQ + 1)) {
                     p.collides = c + 1;
                     i = (i == 0) ? m : i - 1;          // cyclically traverse
                 }
@@ -455,24 +457,24 @@
 
         for (Node q;;) {
             if ((q = slot) != null) {
-                if (U.compareAndSwapObject(this, SLOT, q, null)) {
+                if (SLOT.compareAndSet(this, q, null)) {
                     Object v = q.item;
                     q.match = item;
                     Thread w = q.parked;
                     if (w != null)
-                        U.unpark(w);
+                        LockSupport.unpark(w);
                     return v;
                 }
                 // create arena on contention, but continue until slot null
                 if (NCPU > 1 && bound == 0 &&
-                    U.compareAndSwapInt(this, BOUND, 0, SEQ))
+                    BOUND.compareAndSet(this, 0, SEQ))
                     arena = new Node[(FULL + 2) << ASHIFT];
             }
             else if (arena != null)
                 return null; // caller must reroute to arenaExchange
             else {
                 p.item = item;
-                if (U.compareAndSwapObject(this, SLOT, null, p))
+                if (SLOT.compareAndSet(this, null, p))
                     break;
                 p.item = null;
             }
@@ -495,19 +497,21 @@
                 spins = SPINS;
             else if (!t.isInterrupted() && arena == null &&
                      (!timed || (ns = end - System.nanoTime()) > 0L)) {
-                U.putObject(t, BLOCKER, this);
                 p.parked = t;
-                if (slot == p)
-                    U.park(false, ns);
+                if (slot == p) {
+                    if (ns == 0L)
+                        LockSupport.park(this);
+                    else
+                        LockSupport.parkNanos(this, ns);
+                }
                 p.parked = null;
-                U.putObject(t, BLOCKER, null);
             }
-            else if (U.compareAndSwapObject(this, SLOT, p, null)) {
+            else if (SLOT.compareAndSet(this, p, null)) {
                 v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
                 break;
             }
         }
-        U.putObjectRelease(p, MATCH, null);
+        MATCH.setRelease(p, null);
         p.item = null;
         p.hash = h;
         return v;
@@ -556,8 +560,9 @@
     @SuppressWarnings("unchecked")
     public V exchange(V x) throws InterruptedException {
         Object v;
+        Node[] a;
         Object item = (x == null) ? NULL_ITEM : x; // translate null args
-        if ((arena != null ||
+        if (((a = arena) != null ||
              (v = slotExchange(item, false, 0L)) == null) &&
             ((Thread.interrupted() || // disambiguates null return
               (v = arenaExchange(item, false, 0L)) == null)))
@@ -623,31 +628,18 @@
         return (v == NULL_ITEM) ? null : (V)v;
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long BOUND;
-    private static final long SLOT;
-    private static final long MATCH;
-    private static final long BLOCKER;
-    private static final int ABASE;
+    // VarHandle mechanics
+    private static final VarHandle BOUND;
+    private static final VarHandle SLOT;
+    private static final VarHandle MATCH;
+    private static final VarHandle AA;
     static {
         try {
-            BOUND = U.objectFieldOffset
-                (Exchanger.class.getDeclaredField("bound"));
-            SLOT = U.objectFieldOffset
-                (Exchanger.class.getDeclaredField("slot"));
-
-            MATCH = U.objectFieldOffset
-                (Node.class.getDeclaredField("match"));
-
-            BLOCKER = U.objectFieldOffset
-                (Thread.class.getDeclaredField("parkBlocker"));
-
-            int scale = U.arrayIndexScale(Node[].class);
-            if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
-                throw new Error("Unsupported array scale");
-            // ABASE absorbs padding in front of element 0
-            ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            BOUND = l.findVarHandle(Exchanger.class, "bound", int.class);
+            SLOT = l.findVarHandle(Exchanger.class, "slot", Node.class);
+            MATCH = l.findVarHandle(Node.class, "match", Object.class);
+            AA = MethodHandles.arrayElementVarHandle(Node[].class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Wed Jul 05 22:00:06 2017 +0200
@@ -36,6 +36,8 @@
 package java.util.concurrent;
 
 import java.lang.Thread.UncaughtExceptionHandler;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.security.AccessControlContext;
 import java.security.Permissions;
 import java.security.ProtectionDomain;
@@ -44,7 +46,11 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Predicate;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.ForkJoinWorkerThread;
 import java.util.concurrent.locks.LockSupport;
 
 /**
@@ -81,7 +87,9 @@
  * However, no such adjustments are guaranteed in the face of blocked
  * I/O or other unmanaged synchronization. The nested {@link
  * ManagedBlocker} interface enables extension of the kinds of
- * synchronization accommodated.
+ * synchronization accommodated. The default policies may be
+ * overridden using a constructor with parameters corresponding to
+ * those documented in class {@link ThreadPoolExecutor}.
  *
  * <p>In addition to execution and lifecycle control methods, this
  * class provides status check methods (for example
@@ -162,7 +170,6 @@
  * @since 1.7
  * @author Doug Lea
  */
-@jdk.internal.vm.annotation.Contended
 public class ForkJoinPool extends AbstractExecutorService {
 
     /*
@@ -229,10 +236,9 @@
      *        (CAS slot to null))
      *           increment base and return task;
      *
-     * There are several variants of each of these; for example most
-     * versions of poll pre-screen the CAS by rechecking that the base
-     * has not changed since reading the slot, and most methods only
-     * attempt the CAS if base appears not to be equal to top.
+     * There are several variants of each of these. In particular,
+     * almost all uses of poll occur within scan operations that also
+     * interleave contention tracking (with associated code sprawl.)
      *
      * Memory ordering.  See "Correct and Efficient Work-Stealing for
      * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
@@ -264,10 +270,7 @@
      * thief chooses a different random victim target to try next. So,
      * in order for one thief to progress, it suffices for any
      * in-progress poll or new push on any empty queue to
-     * complete. (This is why we normally use method pollAt and its
-     * variants that try once at the apparent base index, else
-     * consider alternative actions, rather than method poll, which
-     * retries.)
+     * complete.
      *
      * This approach also enables support of a user mode in which
      * local task processing is in FIFO, not LIFO order, simply by
@@ -282,16 +285,13 @@
      * choosing existing queues, and may be randomly repositioned upon
      * contention with other submitters.  In essence, submitters act
      * like workers except that they are restricted to executing local
-     * tasks that they submitted (or in the case of CountedCompleters,
-     * others with the same root task).  Insertion of tasks in shared
-     * mode requires a lock but we use only a simple spinlock (using
-     * field qlock), because submitters encountering a busy queue move
-     * on to try or create other queues -- they block only when
-     * creating and registering new queues. Because it is used only as
-     * a spinlock, unlocking requires only a "releasing" store (using
-     * putIntRelease).  The qlock is also used during termination
-     * detection, in which case it is forced to a negative
-     * non-lockable value.
+     * tasks that they submitted.  Insertion of tasks in shared mode
+     * requires a lock but we use only a simple spinlock (using field
+     * phase), because submitters encountering a busy queue move to a
+     * different position to use or create other queues -- they block
+     * only when creating and registering new queues. Because it is
+     * used only as a spinlock, unlocking requires only a "releasing"
+     * store (using setRelease).
      *
      * Management
      * ==========
@@ -305,42 +305,34 @@
      * There are only a few properties that we can globally track or
      * maintain, so we pack them into a small number of variables,
      * often maintaining atomicity without blocking or locking.
-     * Nearly all essentially atomic control state is held in two
+     * Nearly all essentially atomic control state is held in a few
      * volatile variables that are by far most often read (not
-     * written) as status and consistency checks. (Also, field
-     * "config" holds unchanging configuration state.)
+     * written) as status and consistency checks. We pack as much
+     * information into them as we can.
      *
      * Field "ctl" contains 64 bits holding information needed to
-     * atomically decide to add, inactivate, enqueue (on an event
-     * queue), dequeue, and/or re-activate workers.  To enable this
+     * atomically decide to add, enqueue (on an event queue), and
+     * dequeue (and release)-activate workers.  To enable this
      * packing, we restrict maximum parallelism to (1<<15)-1 (which is
      * far in excess of normal operating range) to allow ids, counts,
      * and their negations (used for thresholding) to fit into 16bit
      * subfields.
      *
-     * Field "runState" holds lifetime status, atomically and
-     * monotonically setting STARTED, SHUTDOWN, STOP, and finally
-     * TERMINATED bits.
-     *
-     * Field "auxState" is a ReentrantLock subclass that also
-     * opportunistically holds some other bookkeeping fields accessed
-     * only when locked.  It is mainly used to lock (infrequent)
-     * updates to workQueues.  The auxState instance is itself lazily
-     * constructed (see tryInitialize), requiring a double-check-style
-     * bootstrapping use of field runState, and locking a private
-     * static.
+     * Field "mode" holds configuration parameters as well as lifetime
+     * status, atomically and monotonically setting SHUTDOWN, STOP,
+     * and finally TERMINATED bits.
      *
      * Field "workQueues" holds references to WorkQueues.  It is
-     * updated (only during worker creation and termination) under the
-     * lock, but is otherwise concurrently readable, and accessed
-     * directly. We also ensure that reads of the array reference
-     * itself never become too stale (for example, re-reading before
-     * each scan). To simplify index-based operations, the array size
-     * is always a power of two, and all readers must tolerate null
-     * slots. Worker queues are at odd indices. Shared (submission)
-     * queues are at even indices, up to a maximum of 64 slots, to
-     * limit growth even if array needs to expand to add more
-     * workers. Grouping them together in this way simplifies and
+     * updated (only during worker creation and termination) under
+     * lock (using field workerNamePrefix as lock), but is otherwise
+     * concurrently readable, and accessed directly. We also ensure
+     * that uses of the array reference itself never become too stale
+     * in case of resizing.  To simplify index-based operations, the
+     * array size is always a power of two, and all readers must
+     * tolerate null slots. Worker queues are at odd indices. Shared
+     * (submission) queues are at even indices, up to a maximum of 64
+     * slots, to limit growth even if array needs to expand to add
+     * more workers. Grouping them together in this way simplifies and
      * speeds up task scanning.
      *
      * All worker thread creation is on-demand, triggered by task
@@ -360,30 +352,37 @@
      * workers unless there appear to be tasks available.  On the
      * other hand, we must quickly prod them into action when new
      * tasks are submitted or generated. In many usages, ramp-up time
-     * to activate workers is the main limiting factor in overall
-     * performance, which is compounded at program start-up by JIT
-     * compilation and allocation. So we streamline this as much as
-     * possible.
+     * is the main limiting factor in overall performance, which is
+     * compounded at program start-up by JIT compilation and
+     * allocation. So we streamline this as much as possible.
      *
-     * The "ctl" field atomically maintains active and total worker
-     * counts as well as a queue to place waiting threads so they can
-     * be located for signalling. Active counts also play the role of
-     * quiescence indicators, so are decremented when workers believe
-     * that there are no more tasks to execute. The "queue" is
-     * actually a form of Treiber stack.  A stack is ideal for
-     * activating threads in most-recently used order. This improves
+     * The "ctl" field atomically maintains total worker and
+     * "released" worker counts, plus the head of the available worker
+     * queue (actually stack, represented by the lower 32bit subfield
+     * of ctl).  Released workers are those known to be scanning for
+     * and/or running tasks. Unreleased ("available") workers are
+     * recorded in the ctl stack. These workers are made available for
+     * signalling by enqueuing in ctl (see method runWorker).  The
+     * "queue" is a form of Treiber stack. This is ideal for
+     * activating threads in most-recently used order, and improves
      * performance and locality, outweighing the disadvantages of
      * being prone to contention and inability to release a worker
-     * unless it is topmost on stack.  We block/unblock workers after
-     * pushing on the idle worker stack (represented by the lower
-     * 32bit subfield of ctl) when they cannot find work.  The top
-     * stack state holds the value of the "scanState" field of the
-     * worker: its index and status, plus a version counter that, in
-     * addition to the count subfields (also serving as version
-     * stamps) provide protection against Treiber stack ABA effects.
+     * unless it is topmost on stack.  To avoid missed signal problems
+     * inherent in any wait/signal design, available workers rescan
+     * for (and if found run) tasks after enqueuing.  Normally their
+     * release status will be updated while doing so, but the released
+     * worker ctl count may underestimate the number of active
+     * threads. (However, it is still possible to determine quiescence
+     * via a validation traversal -- see isQuiescent).  After an
+     * unsuccessful rescan, available workers are blocked until
+     * signalled (see signalWork).  The top stack state holds the
+     * value of the "phase" field of the worker: its index and status,
+     * plus a version counter that, in addition to the count subfields
+     * (also serving as version stamps) provide protection against
+     * Treiber stack ABA effects.
      *
-     * Creating workers. To create a worker, we pre-increment total
-     * count (serving as a reservation), and attempt to construct a
+     * Creating workers. To create a worker, we pre-increment counts
+     * (serving as a reservation), and attempt to construct a
      * ForkJoinWorkerThread via its factory. Upon construction, the
      * new thread invokes registerWorker, where it constructs a
      * WorkQueue and is assigned an index in the workQueues array
@@ -405,16 +404,15 @@
      * submission queues for existing external threads (see
      * externalPush).
      *
-     * WorkQueue field scanState is used by both workers and the pool
-     * to manage and track whether a worker is UNSIGNALLED (possibly
-     * blocked waiting for a signal).  When a worker is inactivated,
-     * its scanState field is set, and is prevented from executing
-     * tasks, even though it must scan once for them to avoid queuing
-     * races. Note that scanState updates lag queue CAS releases so
-     * usage requires care. When queued, the lower 16 bits of
-     * scanState must hold its pool index. So we place the index there
-     * upon initialization (see registerWorker) and otherwise keep it
-     * there or restore it when necessary.
+     * WorkQueue field "phase" is used by both workers and the pool to
+     * manage and track whether a worker is UNSIGNALLED (possibly
+     * blocked waiting for a signal).  When a worker is enqueued its
+     * phase field is set. Note that phase field updates lag queue CAS
+     * releases so usage requires care -- seeing a negative phase does
+     * not guarantee that the worker is available. When queued, the
+     * lower 16 bits of scanState must hold its pool index. So we
+     * place the index there upon initialization (see registerWorker)
+     * and otherwise keep it there or restore it when necessary.
      *
      * The ctl field also serves as the basis for memory
      * synchronization surrounding activation. This uses a more
@@ -423,15 +421,14 @@
      * if to its current value).  This would be extremely costly. So
      * we relax it in several ways: (1) Producers only signal when
      * their queue is empty. Other workers propagate this signal (in
-     * method scan) when they find tasks. (2) Workers only enqueue
-     * after scanning (see below) and not finding any tasks.  (3)
-     * Rather than CASing ctl to its current value in the common case
-     * where no action is required, we reduce write contention by
-     * equivalently prefacing signalWork when called by an external
-     * task producer using a memory access with full-volatile
-     * semantics or a "fullFence". (4) For internal task producers we
-     * rely on the fact that even if no other workers awaken, the
-     * producer itself will eventually see the task and execute it.
+     * method scan) when they find tasks; to further reduce flailing,
+     * each worker signals only one other per activation. (2) Workers
+     * only enqueue after scanning (see below) and not finding any
+     * tasks.  (3) Rather than CASing ctl to its current value in the
+     * common case where no action is required, we reduce write
+     * contention by equivalently prefacing signalWork when called by
+     * an external task producer using a memory access with
+     * full-volatile semantics or a "fullFence".
      *
      * Almost always, too many signals are issued. A task producer
      * cannot in general tell if some existing worker is in the midst
@@ -443,64 +440,40 @@
      * and bookkeeping bottlenecks during ramp-up, ramp-down, and small
      * computations involving only a few workers.
      *
-     * Scanning. Method scan() performs top-level scanning for tasks.
-     * Each scan traverses (and tries to poll from) each queue in
-     * pseudorandom permutation order by randomly selecting an origin
-     * index and a step value.  (The pseudorandom generator need not
-     * have high-quality statistical properties in the long term, but
-     * just within computations; We use 64bit and 32bit Marsaglia
-     * XorShifts, which are cheap and suffice here.)  Scanning also
-     * employs contention reduction: When scanning workers fail a CAS
-     * polling for work, they soon restart with a different
-     * pseudorandom scan order (thus likely retrying at different
-     * intervals). This improves throughput when many threads are
-     * trying to take tasks from few queues.  Scans do not otherwise
-     * explicitly take into account core affinities, loads, cache
-     * localities, etc, However, they do exploit temporal locality
-     * (which usually approximates these) by preferring to re-poll (up
-     * to POLL_LIMIT times) from the same queue after a successful
-     * poll before trying others.  Restricted forms of scanning occur
-     * in methods helpComplete and findNonEmptyStealQueue, and take
-     * similar but simpler forms.
-     *
-     * Deactivation and waiting. Queuing encounters several intrinsic
-     * races; most notably that an inactivating scanning worker can
-     * miss seeing a task produced during a scan.  So when a worker
-     * cannot find a task to steal, it inactivates and enqueues, and
-     * then rescans to ensure that it didn't miss one, reactivating
-     * upon seeing one with probability approximately proportional to
-     * probability of a miss.  (In most cases, the worker will be
-     * signalled before self-signalling, avoiding cascades of multiple
-     * signals for the same task).
-     *
-     * Workers block (in method awaitWork) using park/unpark;
-     * advertising the need for signallers to unpark by setting their
-     * "parker" fields.
+     * Scanning. Method runWorker performs top-level scanning for
+     * tasks.  Each scan traverses and tries to poll from each queue
+     * starting at a random index and circularly stepping. Scans are
+     * not performed in ideal random permutation order, to reduce
+     * cacheline contention.  The pseudorandom generator need not have
+     * high-quality statistical properties in the long term, but just
+     * within computations; We use Marsaglia XorShifts (often via
+     * ThreadLocalRandom.nextSecondarySeed), which are cheap and
+     * suffice. Scanning also employs contention reduction: When
+     * scanning workers fail to extract an apparently existing task,
+     * they soon restart at a different pseudorandom index.  This
+     * improves throughput when many threads are trying to take tasks
+     * from few queues, which can be common in some usages.  Scans do
+     * not otherwise explicitly take into account core affinities,
+     * loads, cache localities, etc, However, they do exploit temporal
+     * locality (which usually approximates these) by preferring to
+     * re-poll (at most #workers times) from the same queue after a
+     * successful poll before trying others.
      *
      * Trimming workers. To release resources after periods of lack of
      * use, a worker starting to wait when the pool is quiescent will
-     * time out and terminate (see awaitWork) if the pool has remained
-     * quiescent for period given by IDLE_TIMEOUT_MS, increasing the
-     * period as the number of threads decreases, eventually removing
-     * all workers.
+     * time out and terminate (see method scan) if the pool has
+     * remained quiescent for period given by field keepAlive.
      *
      * Shutdown and Termination. A call to shutdownNow invokes
      * tryTerminate to atomically set a runState bit. The calling
      * thread, as well as every other worker thereafter terminating,
-     * helps terminate others by setting their (qlock) status,
-     * cancelling their unprocessed tasks, and waking them up, doing
-     * so repeatedly until stable. Calls to non-abrupt shutdown()
-     * preface this by checking whether termination should commence.
-     * This relies primarily on the active count bits of "ctl"
-     * maintaining consensus -- tryTerminate is called from awaitWork
-     * whenever quiescent. However, external submitters do not take
-     * part in this consensus.  So, tryTerminate sweeps through queues
-     * (until stable) to ensure lack of in-flight submissions and
-     * workers about to process them before triggering the "STOP"
-     * phase of termination. (Note: there is an intrinsic conflict if
-     * helpQuiescePool is called when shutdown is enabled. Both wait
-     * for quiescence, but tryTerminate is biased to not trigger until
-     * helpQuiescePool completes.)
+     * helps terminate others by cancelling their unprocessed tasks,
+     * and waking them up, doing so repeatedly until stable. Calls to
+     * non-abrupt shutdown() preface this by checking whether
+     * termination should commence by sweeping through queues (until
+     * stable) to ensure lack of in-flight submissions and workers
+     * about to process them before triggering the "STOP" phase of
+     * termination.
      *
      * Joining Tasks
      * =============
@@ -508,12 +481,12 @@
      * Any of several actions may be taken when one worker is waiting
      * to join a task stolen (or always held) by another.  Because we
      * are multiplexing many tasks on to a pool of workers, we can't
-     * just let them block (as in Thread.join).  We also cannot just
-     * reassign the joiner's run-time stack with another and replace
-     * it later, which would be a form of "continuation", that even if
-     * possible is not necessarily a good idea since we may need both
-     * an unblocked task and its continuation to progress.  Instead we
-     * combine two tactics:
+     * always just let them block (as in Thread.join).  We also cannot
+     * just reassign the joiner's run-time stack with another and
+     * replace it later, which would be a form of "continuation", that
+     * even if possible is not necessarily a good idea since we may
+     * need both an unblocked task and its continuation to progress.
+     * Instead we combine two tactics:
      *
      *   Helping: Arranging for the joiner to execute some task that it
      *      would be running if the steal had not occurred.
@@ -526,79 +499,43 @@
      * helping a hypothetical compensator: If we can readily tell that
      * a possible action of a compensator is to steal and execute the
      * task being joined, the joining thread can do so directly,
-     * without the need for a compensation thread (although at the
-     * expense of larger run-time stacks, but the tradeoff is
-     * typically worthwhile).
+     * without the need for a compensation thread.
      *
      * The ManagedBlocker extension API can't use helping so relies
      * only on compensation in method awaitBlocker.
      *
-     * The algorithm in helpStealer entails a form of "linear
-     * helping".  Each worker records (in field currentSteal) the most
-     * recent task it stole from some other worker (or a submission).
-     * It also records (in field currentJoin) the task it is currently
-     * actively joining. Method helpStealer uses these markers to try
-     * to find a worker to help (i.e., steal back a task from and
-     * execute it) that could hasten completion of the actively joined
-     * task.  Thus, the joiner executes a task that would be on its
-     * own local deque had the to-be-joined task not been stolen. This
-     * is a conservative variant of the approach described in Wagner &
-     * Calder "Leapfrogging: a portable technique for implementing
-     * efficient futures" SIGPLAN Notices, 1993
-     * (http://portal.acm.org/citation.cfm?id=155354). It differs in
-     * that: (1) We only maintain dependency links across workers upon
-     * steals, rather than use per-task bookkeeping.  This sometimes
-     * requires a linear scan of workQueues array to locate stealers,
-     * but often doesn't because stealers leave hints (that may become
-     * stale/wrong) of where to locate them.  It is only a hint
-     * because a worker might have had multiple steals and the hint
-     * records only one of them (usually the most current).  Hinting
-     * isolates cost to when it is needed, rather than adding to
-     * per-task overhead.  (2) It is "shallow", ignoring nesting and
-     * potentially cyclic mutual steals.  (3) It is intentionally
-     * racy: field currentJoin is updated only while actively joining,
-     * which means that we miss links in the chain during long-lived
-     * tasks, GC stalls etc (which is OK since blocking in such cases
-     * is usually a good idea).  (4) We bound the number of attempts
-     * to find work using checksums and fall back to suspending the
-     * worker and if necessary replacing it with another.
+     * The algorithm in awaitJoin entails a form of "linear helping".
+     * Each worker records (in field source) the id of the queue from
+     * which it last stole a task.  The scan in method awaitJoin uses
+     * these markers to try to find a worker to help (i.e., steal back
+     * a task from and execute it) that could hasten completion of the
+     * actively joined task.  Thus, the joiner executes a task that
+     * would be on its own local deque if the to-be-joined task had
+     * not been stolen. This is a conservative variant of the approach
+     * described in Wagner & Calder "Leapfrogging: a portable
+     * technique for implementing efficient futures" SIGPLAN Notices,
+     * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
+     * mainly in that we only record queue ids, not full dependency
+     * links.  This requires a linear scan of the workQueues array to
+     * locate stealers, but isolates cost to when it is needed, rather
+     * than adding to per-task overhead. Searches can fail to locate
+     * stealers GC stalls and the like delay recording sources.
+     * Further, even when accurately identified, stealers might not
+     * ever produce a task that the joiner can in turn help with. So,
+     * compensation is tried upon failure to find tasks to run.
      *
-     * Helping actions for CountedCompleters do not require tracking
-     * currentJoins: Method helpComplete takes and executes any task
-     * with the same root as the task being waited on (preferring
-     * local pops to non-local polls). However, this still entails
-     * some traversal of completer chains, so is less efficient than
-     * using CountedCompleters without explicit joins.
-     *
-     * Compensation does not aim to keep exactly the target
+     * Compensation does not by default aim to keep exactly the target
      * parallelism number of unblocked threads running at any given
      * time. Some previous versions of this class employed immediate
      * compensations for any blocked join. However, in practice, the
      * vast majority of blockages are transient byproducts of GC and
      * other JVM or OS activities that are made worse by replacement.
-     * Currently, compensation is attempted only after validating that
-     * all purportedly active threads are processing tasks by checking
-     * field WorkQueue.scanState, which eliminates most false
-     * positives.  Also, compensation is bypassed (tolerating fewer
-     * threads) in the most common case in which it is rarely
-     * beneficial: when a worker with an empty queue (thus no
-     * continuation tasks) blocks on a join and there still remain
-     * enough threads to ensure liveness.
-     *
-     * Spare threads are removed as soon as they notice that the
-     * target parallelism level has been exceeded, in method
-     * tryDropSpare. (Method scan arranges returns for rechecks upon
-     * each probe via the "bound" parameter.)
-     *
-     * The compensation mechanism may be bounded.  Bounds for the
-     * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
-     * with programming errors and abuse before running out of
-     * resources to do so. In other cases, users may supply factories
-     * that limit thread construction. The effects of bounding in this
-     * pool (like all others) is imprecise.  Total worker counts are
-     * decremented when threads deregister, not when they exit and
-     * resources are reclaimed by the JVM and OS. So the number of
-     * simultaneously live threads may transiently exceed bounds.
+     * Rather than impose arbitrary policies, we allow users to
+     * override the default of only adding threads upon apparent
+     * starvation.  The compensation mechanism may also be bounded.
+     * Bounds for the commonPool (see COMMON_MAX_SPARES) better enable
+     * JVMs to cope with programming errors and abuse before running
+     * out of resources to do so.
      *
      * Common Pool
      * ===========
@@ -606,9 +543,7 @@
      * The static common pool always exists after static
      * initialization.  Since it (or any other created pool) need
      * never be used, we minimize initial construction overhead and
-     * footprint to the setup of about a dozen fields, with no nested
-     * allocation. Most bootstrapping occurs within method
-     * externalSubmit during the first submission to the pool.
+     * footprint to the setup of about a dozen fields.
      *
      * When external threads submit to the common pool, they can
      * perform subtask processing (see externalHelpComplete and
@@ -628,28 +563,22 @@
      * InnocuousForkJoinWorkerThread when there is a SecurityManager
      * present. These workers have no permissions set, do not belong
      * to any user-defined ThreadGroup, and erase all ThreadLocals
-     * after executing any top-level task (see WorkQueue.runTask).
-     * The associated mechanics (mainly in ForkJoinWorkerThread) may
-     * be JVM-dependent and must access particular Thread class fields
-     * to achieve this effect.
+     * after executing any top-level task (see
+     * WorkQueue.afterTopLevelExec).  The associated mechanics (mainly
+     * in ForkJoinWorkerThread) may be JVM-dependent and must access
+     * particular Thread class fields to achieve this effect.
      *
      * Style notes
      * ===========
      *
-     * Memory ordering relies mainly on Unsafe intrinsics that carry
-     * the further responsibility of explicitly performing null- and
-     * bounds- checks otherwise carried out implicitly by JVMs.  This
-     * can be awkward and ugly, but also reflects the need to control
+     * Memory ordering relies mainly on VarHandles.  This can be
+     * awkward and ugly, but also reflects the need to control
      * outcomes across the unusual cases that arise in very racy code
-     * with very few invariants. So these explicit checks would exist
-     * in some form anyway.  All fields are read into locals before
-     * use, and null-checked if they are references.  This is usually
-     * done in a "C"-like style of listing declarations at the heads
-     * of methods or blocks, and using inline assignments on first
-     * encounter.  Array bounds-checks are usually performed by
-     * masking with array.length-1, which relies on the invariant that
-     * these arrays are created with positive lengths, which is itself
-     * paranoically checked. Nearly all explicit checks lead to
+     * with very few invariants. All fields are read into locals
+     * before use, and null-checked if they are references.  This is
+     * usually done in a "C"-like style of listing declarations at the
+     * heads of methods or blocks, and using inline assignments on
+     * first encounter.  Nearly all explicit checks lead to
      * bypass/return, not exception throws, because they may
      * legitimately arise due to cancellation/revocation during
      * shutdown.
@@ -701,10 +630,17 @@
     public static interface ForkJoinWorkerThreadFactory {
         /**
          * Returns a new worker thread operating in the given pool.
+         * Returning null or throwing an exception may result in tasks
+         * never being executed.  If this method throws an exception,
+         * it is relayed to the caller of the method (for example
+         * {@code execute}) causing attempted thread creation. If this
+         * method returns null or throws an exception, it is not
+         * retried until the next attempted creation (for example
+         * another call to {@code execute}).
          *
          * @param pool the pool this thread works in
          * @return the new worker thread, or {@code null} if the request
-         *         to create a thread is rejected
+         *         to create a thread is rejected.
          * @throws NullPointerException if the pool is null
          */
         public ForkJoinWorkerThread newThread(ForkJoinPool pool);
@@ -721,56 +657,35 @@
         }
     }
 
-    /**
-     * Class for artificial tasks that are used to replace the target
-     * of local joins if they are removed from an interior queue slot
-     * in WorkQueue.tryRemoveAndExec. We don't need the proxy to
-     * actually do anything beyond having a unique identity.
-     */
-    private static final class EmptyTask extends ForkJoinTask<Void> {
-        private static final long serialVersionUID = -7721805057305804111L;
-        EmptyTask() { status = ForkJoinTask.NORMAL; } // force done
-        public final Void getRawResult() { return null; }
-        public final void setRawResult(Void x) {}
-        public final boolean exec() { return true; }
-    }
-
-    /**
-     * Additional fields and lock created upon initialization.
-     */
-    private static final class AuxState extends ReentrantLock {
-        private static final long serialVersionUID = -6001602636862214147L;
-        volatile long stealCount;     // cumulative steal count
-        long indexSeed;               // index bits for registerWorker
-        AuxState() {}
-    }
-
     // Constants shared across ForkJoinPool and WorkQueue
 
     // Bounds
+    static final int SWIDTH       = 16;            // width of short
     static final int SMASK        = 0xffff;        // short bits == max index
     static final int MAX_CAP      = 0x7fff;        // max #workers - 1
-    static final int EVENMASK     = 0xfffe;        // even short bits
     static final int SQMASK       = 0x007e;        // max 64 (even) slots
 
-    // Masks and units for WorkQueue.scanState and ctl sp subfield
+    // Masks and units for WorkQueue.phase and ctl sp subfield
     static final int UNSIGNALLED  = 1 << 31;       // must be negative
     static final int SS_SEQ       = 1 << 16;       // version count
+    static final int QLOCK        = 1;             // must be 1
 
-    // Mode bits for ForkJoinPool.config and WorkQueue.config
-    static final int MODE_MASK    = 0xffff << 16;  // top half of int
-    static final int SPARE_WORKER = 1 << 17;       // set if tc > 0 on creation
-    static final int UNREGISTERED = 1 << 18;       // to skip some of deregister
-    static final int FIFO_QUEUE   = 1 << 31;       // must be negative
-    static final int LIFO_QUEUE   = 0;             // for clarity
-    static final int IS_OWNED     = 1;             // low bit 0 if shared
+    // Mode bits and sentinels, some also used in WorkQueue id and.source fields
+    static final int OWNED        = 1;             // queue has owner thread
+    static final int FIFO         = 1 << 16;       // fifo queue or access mode
+    static final int SHUTDOWN     = 1 << 18;
+    static final int TERMINATED   = 1 << 19;
+    static final int STOP         = 1 << 31;       // must be negative
+    static final int QUIET        = 1 << 30;       // not scanning or working
+    static final int DORMANT      = QUIET | UNSIGNALLED;
 
     /**
-     * The maximum number of task executions from the same queue
-     * before checking other queues, bounding unfairness and impact of
-     * infinite user task recursion.  Must be a power of two minus 1.
+     * The maximum number of local polls from the same queue before
+     * checking others. This is a safeguard against infinitely unfair
+     * looping under unbounded user task recursion, and must be larger
+     * than plausible cases of intentional bounded task recursion.
      */
-    static final int POLL_LIMIT = (1 << 10) - 1;
+    static final int POLL_LIMIT = 1 << 10;
 
     /**
      * Queues supporting work-stealing as well as external task
@@ -805,23 +720,16 @@
         static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
 
         // Instance fields
-
-        volatile int scanState;    // versioned, negative if inactive
-        int stackPred;             // pool stack (ctl) predecessor
+        volatile int phase;        // versioned, negative: queued, 1: locked
+        int stackPred;             // pool stack (ctl) predecessor link
         int nsteals;               // number of steals
-        int hint;                  // randomization and stealer index hint
-        int config;                // pool index and mode
-        volatile int qlock;        // 1: locked, < 0: terminate; else 0
+        int id;                    // index, mode, tag
+        volatile int source;       // source queue id, or sentinel
         volatile int base;         // index of next slot for poll
         int top;                   // index of next slot for push
         ForkJoinTask<?>[] array;   // the elements (initially unallocated)
         final ForkJoinPool pool;   // the containing pool (may be null)
         final ForkJoinWorkerThread owner; // owning thread or null if shared
-        volatile Thread parker;    // == owner during call to park; else null
-        volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin
-
-        @jdk.internal.vm.annotation.Contended("group2") // segregate
-        volatile ForkJoinTask<?> currentSteal; // nonnull when running some task
 
         WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) {
             this.pool = pool;
@@ -834,7 +742,7 @@
          * Returns an exportable index (used by ForkJoinWorkerThread).
          */
         final int getPoolIndex() {
-            return (config & 0xffff) >>> 1; // ignore odd/even tag bit
+            return (id & 0xffff) >>> 1; // ignore odd/even tag bit
         }
 
         /**
@@ -851,13 +759,14 @@
          * near-empty queue has at least one unclaimed task.
          */
         final boolean isEmpty() {
-            ForkJoinTask<?>[] a; int n, al, s;
-            return ((n = base - (s = top)) >= 0 || // possibly one task
+            ForkJoinTask<?>[] a; int n, al, b;
+            return ((n = (b = base) - top) >= 0 || // possibly one task
                     (n == -1 && ((a = array) == null ||
                                  (al = a.length) == 0 ||
-                                 a[(al - 1) & (s - 1)] == null)));
+                                 a[(al - 1) & b] == null)));
         }
 
+
         /**
          * Pushes a task. Call only by owner in unshared queues.
          *
@@ -865,17 +774,17 @@
          * @throws RejectedExecutionException if array cannot be resized
          */
         final void push(ForkJoinTask<?> task) {
-            U.storeFence();              // ensure safe publication
-            int s = top, al, d; ForkJoinTask<?>[] a;
+            int s = top; ForkJoinTask<?>[] a; int al, d;
             if ((a = array) != null && (al = a.length) > 0) {
-                a[(al - 1) & s] = task;  // relaxed writes OK
-                top = s + 1;
+                int index = (al - 1) & s;
                 ForkJoinPool p = pool;
+                top = s + 1;
+                QA.setRelease(a, index, task);
                 if ((d = base - s) == 0 && p != null) {
-                    U.fullFence();
+                    VarHandle.fullFence();
                     p.signalWork();
                 }
-                else if (al + d == 1)
+                else if (d + al == 1)
                     growArray();
             }
         }
@@ -887,24 +796,24 @@
          */
         final ForkJoinTask<?>[] growArray() {
             ForkJoinTask<?>[] oldA = array;
-            int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
+            int oldSize = oldA != null ? oldA.length : 0;
+            int size = oldSize > 0 ? oldSize << 1 : INITIAL_QUEUE_CAPACITY;
             if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY)
                 throw new RejectedExecutionException("Queue capacity exceeded");
             int oldMask, t, b;
             ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
-            if (oldA != null && (oldMask = oldA.length - 1) > 0 &&
+            if (oldA != null && (oldMask = oldSize - 1) > 0 &&
                 (t = top) - (b = base) > 0) {
                 int mask = size - 1;
                 do { // emulate poll from old array, push to new array
                     int index = b & oldMask;
-                    long offset = ((long)index << ASHIFT) + ABASE;
                     ForkJoinTask<?> x = (ForkJoinTask<?>)
-                        U.getObjectVolatile(oldA, offset);
+                        QA.getAcquire(oldA, index);
                     if (x != null &&
-                        U.compareAndSwapObject(oldA, offset, x, null))
+                        QA.compareAndSet(oldA, index, x, null))
                         a[b & mask] = x;
                 } while (++b != t);
-                U.storeFence();
+                VarHandle.releaseFence();
             }
             return a;
         }
@@ -917,33 +826,12 @@
             int b = base, s = top, al, i; ForkJoinTask<?>[] a;
             if ((a = array) != null && b != s && (al = a.length) > 0) {
                 int index = (al - 1) & --s;
-                long offset = ((long)index << ASHIFT) + ABASE;
                 ForkJoinTask<?> t = (ForkJoinTask<?>)
-                    U.getObject(a, offset);
+                    QA.get(a, index);
                 if (t != null &&
-                    U.compareAndSwapObject(a, offset, t, null)) {
+                    QA.compareAndSet(a, index, t, null)) {
                     top = s;
-                    return t;
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Takes a task in FIFO order if b is base of queue and a task
-         * can be claimed without contention. Specialized versions
-         * appear in ForkJoinPool methods scan and helpStealer.
-         */
-        final ForkJoinTask<?> pollAt(int b) {
-            ForkJoinTask<?>[] a; int al;
-            if ((a = array) != null && (al = a.length) > 0) {
-                int index = (al - 1) & b;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> t = (ForkJoinTask<?>)
-                    U.getObjectVolatile(a, offset);
-                if (t != null && b++ == base &&
-                    U.compareAndSwapObject(a, offset, t, null)) {
-                    base = b;
+                    VarHandle.releaseFence();
                     return t;
                 }
             }
@@ -959,12 +847,11 @@
                 if ((a = array) != null && (d = b - s) < 0 &&
                     (al = a.length) > 0) {
                     int index = (al - 1) & b;
-                    long offset = ((long)index << ASHIFT) + ABASE;
                     ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        U.getObjectVolatile(a, offset);
+                        QA.getAcquire(a, index);
                     if (b++ == base) {
                         if (t != null) {
-                            if (U.compareAndSwapObject(a, offset, t, null)) {
+                            if (QA.compareAndSet(a, index, t, null)) {
                                 base = b;
                                 return t;
                             }
@@ -983,7 +870,7 @@
          * Takes next task, if one exists, in order specified by mode.
          */
         final ForkJoinTask<?> nextLocalTask() {
-            return (config < 0) ? poll() : pop();
+            return ((id & FIFO) != 0) ? poll() : pop();
         }
 
         /**
@@ -992,7 +879,8 @@
         final ForkJoinTask<?> peek() {
             int al; ForkJoinTask<?>[] a;
             return ((a = array) != null && (al = a.length) > 0) ?
-                a[(al - 1) & (config < 0 ? base : top - 1)] : null;
+                a[(al - 1) &
+                  ((id & FIFO) != 0 ? base : top - 1)] : null;
         }
 
         /**
@@ -1002,9 +890,9 @@
             int b = base, s = top, al; ForkJoinTask<?>[] a;
             if ((a = array) != null && b != s && (al = a.length) > 0) {
                 int index = (al - 1) & --s;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                if (U.compareAndSwapObject(a, offset, task, null)) {
+                if (QA.compareAndSet(a, index, task, null)) {
                     top = s;
+                    VarHandle.releaseFence();
                     return true;
                 }
             }
@@ -1012,105 +900,32 @@
         }
 
         /**
-         * Shared version of push. Fails if already locked.
-         *
-         * @return status: > 0 locked, 0 possibly was empty, < 0 was nonempty
-         */
-        final int sharedPush(ForkJoinTask<?> task) {
-            int stat;
-            if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
-                int b = base, s = top, al, d; ForkJoinTask<?>[] a;
-                if ((a = array) != null && (al = a.length) > 0 &&
-                    al - 1 + (d = b - s) > 0) {
-                    a[(al - 1) & s] = task;
-                    top = s + 1;                 // relaxed writes OK here
-                    qlock = 0;
-                    stat = (d < 0 && b == base) ? d : 0;
-                }
-                else {
-                    growAndSharedPush(task);
-                    stat = 0;
-                }
-            }
-            else
-                stat = 1;
-            return stat;
-        }
-
-        /**
-         * Helper for sharedPush; called only when locked and resize
-         * needed.
-         */
-        private void growAndSharedPush(ForkJoinTask<?> task) {
-            try {
-                growArray();
-                int s = top, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && (al = a.length) > 0) {
-                    a[(al - 1) & s] = task;
-                    top = s + 1;
-                }
-            } finally {
-                qlock = 0;
-            }
-        }
-
-        /**
-         * Shared version of tryUnpush.
-         */
-        final boolean trySharedUnpush(ForkJoinTask<?> task) {
-            boolean popped = false;
-            int s = top - 1, al; ForkJoinTask<?>[] a;
-            if ((a = array) != null && (al = a.length) > 0) {
-                int index = (al - 1) & s;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> t = (ForkJoinTask<?>) U.getObject(a, offset);
-                if (t == task &&
-                    U.compareAndSwapInt(this, QLOCK, 0, 1)) {
-                    if (top == s + 1 && array == a &&
-                        U.compareAndSwapObject(a, offset, task, null)) {
-                        popped = true;
-                        top = s;
-                    }
-                    U.putIntRelease(this, QLOCK, 0);
-                }
-            }
-            return popped;
-        }
-
-        /**
          * Removes and cancels all known tasks, ignoring any exceptions.
          */
         final void cancelAll() {
-            ForkJoinTask<?> t;
-            if ((t = currentJoin) != null) {
-                currentJoin = null;
-                ForkJoinTask.cancelIgnoringExceptions(t);
-            }
-            if ((t = currentSteal) != null) {
-                currentSteal = null;
-                ForkJoinTask.cancelIgnoringExceptions(t);
-            }
-            while ((t = poll()) != null)
+            for (ForkJoinTask<?> t; (t = poll()) != null; )
                 ForkJoinTask.cancelIgnoringExceptions(t);
         }
 
         // Specialized execution methods
 
         /**
-         * Pops and executes up to POLL_LIMIT tasks or until empty.
+         * Pops and executes up to limit consecutive tasks or until empty.
+         *
+         * @param limit max runs, or zero for no limit
          */
-        final void localPopAndExec() {
-            for (int nexec = 0;;) {
+        final void localPopAndExec(int limit) {
+            for (;;) {
                 int b = base, s = top, al; ForkJoinTask<?>[] a;
                 if ((a = array) != null && b != s && (al = a.length) > 0) {
                     int index = (al - 1) & --s;
-                    long offset = ((long)index << ASHIFT) + ABASE;
                     ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        U.getAndSetObject(a, offset, null);
+                        QA.getAndSet(a, index, null);
                     if (t != null) {
                         top = s;
-                        (currentSteal = t).doExec();
-                        if (++nexec > POLL_LIMIT)
+                        VarHandle.releaseFence();
+                        t.doExec();
+                        if (limit != 0 && --limit == 0)
                             break;
                     }
                     else
@@ -1122,22 +937,28 @@
         }
 
         /**
-         * Polls and executes up to POLL_LIMIT tasks or until empty.
+         * Polls and executes up to limit consecutive tasks or until empty.
+         *
+         * @param limit, or zero for no limit
          */
-        final void localPollAndExec() {
-            for (int nexec = 0;;) {
-                int b = base, s = top, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && b != s && (al = a.length) > 0) {
+        final void localPollAndExec(int limit) {
+            for (int polls = 0;;) {
+                int b = base, s = top, d, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (d = b - s) < 0 &&
+                    (al = a.length) > 0) {
                     int index = (al - 1) & b++;
-                    long offset = ((long)index << ASHIFT) + ABASE;
                     ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        U.getAndSetObject(a, offset, null);
+                        QA.getAndSet(a, index, null);
                     if (t != null) {
                         base = b;
                         t.doExec();
-                        if (++nexec > POLL_LIMIT)
+                        if (limit != 0 && ++polls == limit)
                             break;
                     }
+                    else if (d == -1)
+                        break;     // now empty
+                    else
+                        polls = 0; // stolen; reset
                 }
                 else
                     break;
@@ -1145,188 +966,156 @@
         }
 
         /**
-         * Executes the given task and (some) remaining local tasks.
+         * If present, removes task from queue and executes it.
          */
-        final void runTask(ForkJoinTask<?> task) {
-            if (task != null) {
-                task.doExec();
-                if (config < 0)
-                    localPollAndExec();
-                else
-                    localPopAndExec();
-                int ns = ++nsteals;
-                ForkJoinWorkerThread thread = owner;
-                currentSteal = null;
-                if (ns < 0)           // collect on overflow
-                    transferStealCount(pool);
-                if (thread != null)
-                    thread.afterTopLevelExec();
-            }
-        }
-
-        /**
-         * Adds steal count to pool steal count if it exists, and resets.
-         */
-        final void transferStealCount(ForkJoinPool p) {
-            AuxState aux;
-            if (p != null && (aux = p.auxState) != null) {
-                long s = nsteals;
-                nsteals = 0;            // if negative, correct for overflow
-                if (s < 0) s = Integer.MAX_VALUE;
-                aux.lock();
-                try {
-                    aux.stealCount += s;
-                } finally {
-                    aux.unlock();
+        final void tryRemoveAndExec(ForkJoinTask<?> task) {
+            ForkJoinTask<?>[] wa; int s, wal;
+            if (base - (s = top) < 0 && // traverse from top
+                (wa = array) != null && (wal = wa.length) > 0) {
+                for (int m = wal - 1, ns = s - 1, i = ns; ; --i) {
+                    int index = i & m;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        QA.get(wa, index);
+                    if (t == null)
+                        break;
+                    else if (t == task) {
+                        if (QA.compareAndSet(wa, index, t, null)) {
+                            top = ns;   // safely shift down
+                            for (int j = i; j != ns; ++j) {
+                                ForkJoinTask<?> f;
+                                int pindex = (j + 1) & m;
+                                f = (ForkJoinTask<?>)QA.get(wa, pindex);
+                                QA.setVolatile(wa, pindex, null);
+                                int jindex = j & m;
+                                QA.setRelease(wa, jindex, f);
+                            }
+                            VarHandle.releaseFence();
+                            t.doExec();
+                        }
+                        break;
+                    }
                 }
             }
         }
 
         /**
-         * If present, removes from queue and executes the given task,
-         * or any other cancelled task. Used only by awaitJoin.
+         * Tries to steal and run tasks within the target's
+         * computation until done, not found, or limit exceeded.
          *
-         * @return true if queue empty and task not known to be done
+         * @param task root of CountedCompleter computation
+         * @param limit max runs, or zero for no limit
+         * @return task status on exit
          */
-        final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
-            if (task != null && task.status >= 0) {
-                int b, s, d, al; ForkJoinTask<?>[] a;
-                while ((d = (b = base) - (s = top)) < 0 &&
-                       (a = array) != null && (al = a.length) > 0) {
-                    for (;;) {      // traverse from s to b
-                        int index = --s & (al - 1);
-                        long offset = (index << ASHIFT) + ABASE;
-                        ForkJoinTask<?> t = (ForkJoinTask<?>)
-                            U.getObjectVolatile(a, offset);
-                        if (t == null)
-                            break;                   // restart
-                        else if (t == task) {
-                            boolean removed = false;
-                            if (s + 1 == top) {      // pop
-                                if (U.compareAndSwapObject(a, offset, t, null)) {
-                                    top = s;
-                                    removed = true;
+        final int localHelpCC(CountedCompleter<?> task, int limit) {
+            int status = 0;
+            if (task != null && (status = task.status) >= 0) {
+                for (;;) {
+                    boolean help = false;
+                    int b = base, s = top, al; ForkJoinTask<?>[] a;
+                    if ((a = array) != null && b != s && (al = a.length) > 0) {
+                        int index = (al - 1) & (s - 1);
+                        ForkJoinTask<?> o = (ForkJoinTask<?>)
+                            QA.get(a, index);
+                        if (o instanceof CountedCompleter) {
+                            CountedCompleter<?> t = (CountedCompleter<?>)o;
+                            for (CountedCompleter<?> f = t;;) {
+                                if (f != task) {
+                                    if ((f = f.completer) == null) // try parent
+                                        break;
+                                }
+                                else {
+                                    if (QA.compareAndSet(a, index, t, null)) {
+                                        top = s - 1;
+                                        VarHandle.releaseFence();
+                                        t.doExec();
+                                        help = true;
+                                    }
+                                    break;
                                 }
                             }
-                            else if (base == b)      // replace with proxy
-                                removed = U.compareAndSwapObject(a, offset, t,
-                                                                 new EmptyTask());
-                            if (removed) {
-                                ForkJoinTask<?> ps = currentSteal;
-                                (currentSteal = task).doExec();
-                                currentSteal = ps;
-                            }
-                            break;
-                        }
-                        else if (t.status < 0 && s + 1 == top) {
-                            if (U.compareAndSwapObject(a, offset, t, null)) {
-                                top = s;
-                            }
-                            break;                  // was cancelled
-                        }
-                        else if (++d == 0) {
-                            if (base != b)          // rescan
-                                break;
-                            return false;
                         }
                     }
-                    if (task.status < 0)
-                        return false;
+                    if ((status = task.status) < 0 || !help ||
+                        (limit != 0 && --limit == 0))
+                        break;
                 }
             }
-            return true;
+            return status;
+        }
+
+        // Operations on shared queues
+
+        /**
+         * Tries to lock shared queue by CASing phase field.
+         */
+        final boolean tryLockSharedQueue() {
+            return PHASE.compareAndSet(this, 0, QLOCK);
         }
 
         /**
-         * Pops task if in the same CC computation as the given task,
-         * in either shared or owned mode. Used only by helpComplete.
+         * Shared version of tryUnpush.
          */
-        final CountedCompleter<?> popCC(CountedCompleter<?> task, int mode) {
-            int b = base, s = top, al; ForkJoinTask<?>[] a;
-            if ((a = array) != null && b != s && (al = a.length) > 0) {
-                int index = (al - 1) & (s - 1);
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> o = (ForkJoinTask<?>)
-                    U.getObjectVolatile(a, offset);
-                if (o instanceof CountedCompleter) {
-                    CountedCompleter<?> t = (CountedCompleter<?>)o;
-                    for (CountedCompleter<?> r = t;;) {
-                        if (r == task) {
-                            if ((mode & IS_OWNED) == 0) {
-                                boolean popped = false;
-                                if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
-                                    if (top == s && array == a &&
-                                        U.compareAndSwapObject(a, offset,
-                                                               t, null)) {
-                                        popped = true;
-                                        top = s - 1;
-                                    }
-                                    U.putIntRelease(this, QLOCK, 0);
-                                    if (popped)
-                                        return t;
-                                }
-                            }
-                            else if (U.compareAndSwapObject(a, offset,
-                                                            t, null)) {
-                                top = s - 1;
-                                return t;
-                            }
-                            break;
-                        }
-                        else if ((r = r.completer) == null) // try parent
-                            break;
+        final boolean trySharedUnpush(ForkJoinTask<?> task) {
+            boolean popped = false;
+            int s = top - 1, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (al = a.length) > 0) {
+                int index = (al - 1) & s;
+                ForkJoinTask<?> t = (ForkJoinTask<?>) QA.get(a, index);
+                if (t == task &&
+                    PHASE.compareAndSet(this, 0, QLOCK)) {
+                    if (top == s + 1 && array == a &&
+                        QA.compareAndSet(a, index, task, null)) {
+                        popped = true;
+                        top = s;
                     }
+                    PHASE.setRelease(this, 0);
                 }
             }
-            return null;
+            return popped;
         }
 
         /**
-         * Steals and runs a task in the same CC computation as the
-         * given task if one exists and can be taken without
-         * contention. Otherwise returns a checksum/control value for
-         * use by method helpComplete.
-         *
-         * @return 1 if successful, 2 if retryable (lost to another
-         * stealer), -1 if non-empty but no matching task found, else
-         * the base index, forced negative.
+         * Shared version of localHelpCC.
          */
-        final int pollAndExecCC(CountedCompleter<?> task) {
-            ForkJoinTask<?>[] a;
-            int b = base, s = top, al, h;
-            if ((a = array) != null && b != s && (al = a.length) > 0) {
-                int index = (al - 1) & b;
-                long offset = ((long)index << ASHIFT) + ABASE;
-                ForkJoinTask<?> o = (ForkJoinTask<?>)
-                    U.getObjectVolatile(a, offset);
-                if (o == null)
-                    h = 2;                      // retryable
-                else if (!(o instanceof CountedCompleter))
-                    h = -1;                     // unmatchable
-                else {
-                    CountedCompleter<?> t = (CountedCompleter<?>)o;
-                    for (CountedCompleter<?> r = t;;) {
-                        if (r == task) {
-                            if (b++ == base &&
-                                U.compareAndSwapObject(a, offset, t, null)) {
-                                base = b;
-                                t.doExec();
-                                h = 1;          // success
+        final int sharedHelpCC(CountedCompleter<?> task, int limit) {
+            int status = 0;
+            if (task != null && (status = task.status) >= 0) {
+                for (;;) {
+                    boolean help = false;
+                    int b = base, s = top, al; ForkJoinTask<?>[] a;
+                    if ((a = array) != null && b != s && (al = a.length) > 0) {
+                        int index = (al - 1) & (s - 1);
+                        ForkJoinTask<?> o = (ForkJoinTask<?>)
+                            QA.get(a, index);
+                        if (o instanceof CountedCompleter) {
+                            CountedCompleter<?> t = (CountedCompleter<?>)o;
+                            for (CountedCompleter<?> f = t;;) {
+                                if (f != task) {
+                                    if ((f = f.completer) == null)
+                                        break;
+                                }
+                                else {
+                                    if (PHASE.compareAndSet(this, 0, QLOCK)) {
+                                        if (top == s && array == a &&
+                                            QA.compareAndSet(a, index, t, null)) {
+                                            help = true;
+                                            top = s - 1;
+                                        }
+                                        PHASE.setRelease(this, 0);
+                                        if (help)
+                                            t.doExec();
+                                    }
+                                    break;
+                                }
                             }
-                            else
-                                h = 2;          // lost CAS
-                            break;
-                        }
-                        else if ((r = r.completer) == null) {
-                            h = -1;             // unmatched
-                            break;
                         }
                     }
+                    if ((status = task.status) < 0 || !help ||
+                        (limit != 0 && --limit == 0))
+                        break;
                 }
             }
-            else
-                h = b | Integer.MIN_VALUE;      // to sense movement on re-poll
-            return h;
+            return status;
         }
 
         /**
@@ -1334,27 +1123,18 @@
          */
         final boolean isApparentlyUnblocked() {
             Thread wt; Thread.State s;
-            return (scanState >= 0 &&
-                    (wt = owner) != null &&
+            return ((wt = owner) != null &&
                     (s = wt.getState()) != Thread.State.BLOCKED &&
                     s != Thread.State.WAITING &&
                     s != Thread.State.TIMED_WAITING);
         }
 
-        // Unsafe mechanics. Note that some are (and must be) the same as in FJP
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long QLOCK;
-        private static final int ABASE;
-        private static final int ASHIFT;
+        // VarHandle mechanics.
+        private static final VarHandle PHASE;
         static {
             try {
-                QLOCK = U.objectFieldOffset
-                    (WorkQueue.class.getDeclaredField("qlock"));
-                ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
-                int scale = U.arrayIndexScale(ForkJoinTask[].class);
-                if ((scale & (scale - 1)) != 0)
-                    throw new Error("array index scale not a power of two");
-                ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                PHASE = l.findVarHandle(WorkQueue.class, "phase", int.class);
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
@@ -1372,7 +1152,7 @@
 
     /**
      * Permission required for callers of methods that may start or
-     * kill threads.  Also used as a static lock in tryInitialize.
+     * kill threads.
      */
     static final RuntimePermission modifyThreadPermission;
 
@@ -1413,18 +1193,15 @@
     // static configuration constants
 
     /**
-     * Initial timeout value (in milliseconds) for the thread
-     * triggering quiescence to park waiting for new work. On timeout,
-     * the thread will instead try to shrink the number of workers.
-     * The value should be large enough to avoid overly aggressive
-     * shrinkage during most transient stalls (long GCs etc).
+     * Default idle timeout value (in milliseconds) for the thread
+     * triggering quiescence to park waiting for new work
      */
-    private static final long IDLE_TIMEOUT_MS = 2000L; // 2sec
+    private static final long DEFAULT_KEEPALIVE = 60000L;
 
     /**
-     * Tolerance for idle timeouts, to cope with timer undershoots.
+     * Undershoot tolerance for idle timeouts
      */
-    private static final long TIMEOUT_SLOP_MS =   20L; // 20ms
+    private static final long TIMEOUT_SLOP = 20L;
 
     /**
      * The default value for COMMON_MAX_SPARES.  Overridable using the
@@ -1444,7 +1221,7 @@
 
     /*
      * Bits and masks for field ctl, packed with 4 16 bit subfields:
-     * AC: Number of active running workers minus target parallelism
+     * RC: Number of released (unqueued) workers minus target parallelism
      * TC: Number of total workers minus target parallelism
      * SS: version count and status of top waiting thread
      * ID: poolIndex of top of Treiber stack of waiters
@@ -1453,26 +1230,30 @@
      * (including version bits) as sp=(int)ctl.  The offsets of counts
      * by the target parallelism and the positionings of fields makes
      * it possible to perform the most common checks via sign tests of
-     * fields: When ac is negative, there are not enough active
+     * fields: When ac is negative, there are not enough unqueued
      * workers, when tc is negative, there are not enough total
      * workers.  When sp is non-zero, there are waiting workers.  To
      * deal with possibly negative fields, we use casts in and out of
      * "short" and/or signed shifts to maintain signedness.
      *
-     * Because it occupies uppermost bits, we can add one active count
-     * using getAndAddLong of AC_UNIT, rather than CAS, when returning
+     * Because it occupies uppermost bits, we can add one release count
+     * using getAndAddLong of RC_UNIT, rather than CAS, when returning
      * from a blocked join.  Other updates entail multiple subfields
      * and masking, requiring CAS.
+     *
+     * The limits packed in field "bounds" are also offset by the
+     * parallelism level to make them comparable to the ctl rc and tc
+     * fields.
      */
 
     // Lower and upper word masks
     private static final long SP_MASK    = 0xffffffffL;
     private static final long UC_MASK    = ~SP_MASK;
 
-    // Active counts
-    private static final int  AC_SHIFT   = 48;
-    private static final long AC_UNIT    = 0x0001L << AC_SHIFT;
-    private static final long AC_MASK    = 0xffffL << AC_SHIFT;
+    // Release counts
+    private static final int  RC_SHIFT   = 48;
+    private static final long RC_UNIT    = 0x0001L << RC_SHIFT;
+    private static final long RC_MASK    = 0xffffL << RC_SHIFT;
 
     // Total counts
     private static final int  TC_SHIFT   = 32;
@@ -1480,52 +1261,21 @@
     private static final long TC_MASK    = 0xffffL << TC_SHIFT;
     private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
 
-    // runState bits: SHUTDOWN must be negative, others arbitrary powers of two
-    private static final int  STARTED    = 1;
-    private static final int  STOP       = 1 << 1;
-    private static final int  TERMINATED = 1 << 2;
-    private static final int  SHUTDOWN   = 1 << 31;
+    // Instance fields
 
-    // Instance fields
-    volatile long ctl;                   // main pool control
-    volatile int runState;
-    final int config;                    // parallelism, mode
-    AuxState auxState;                   // lock, steal counts
-    volatile WorkQueue[] workQueues;     // main registry
-    final String workerNamePrefix;       // to create worker name string
+    volatile long stealCount;            // collects worker nsteals
+    final long keepAlive;                // milliseconds before dropping if idle
+    int indexSeed;                       // next worker index
+    final int bounds;                    // min, max threads packed as shorts
+    volatile int mode;                   // parallelism, runstate, queue mode
+    WorkQueue[] workQueues;              // main registry
+    final String workerNamePrefix;       // for worker thread string; sync lock
     final ForkJoinWorkerThreadFactory factory;
     final UncaughtExceptionHandler ueh;  // per-worker UEH
+    final Predicate<? super ForkJoinPool> saturate;
 
-    /**
-     * Instantiates fields upon first submission, or upon shutdown if
-     * no submissions. If checkTermination true, also responds to
-     * termination by external calls submitting tasks.
-     */
-    private void tryInitialize(boolean checkTermination) {
-        if (runState == 0) { // bootstrap by locking static field
-            int p = config & SMASK;
-            int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots
-            n |= n >>> 1;    // create workQueues array with size a power of two
-            n |= n >>> 2;
-            n |= n >>> 4;
-            n |= n >>> 8;
-            n |= n >>> 16;
-            n = ((n + 1) << 1) & SMASK;
-            AuxState aux = new AuxState();
-            WorkQueue[] ws = new WorkQueue[n];
-            synchronized (modifyThreadPermission) { // double-check
-                if (runState == 0) {
-                    workQueues = ws;
-                    auxState = aux;
-                    runState = STARTED;
-                }
-            }
-        }
-        if (checkTermination && runState < 0) {
-            tryTerminate(false, false); // help terminate
-            throw new RejectedExecutionException();
-        }
-    }
+    @jdk.internal.vm.annotation.Contended("fjpctl") // segregate
+    volatile long ctl;                   // main pool control
 
     // Creating, registering and deregistering workers
 
@@ -1534,18 +1284,14 @@
      * count has already been incremented as a reservation.  Invokes
      * deregisterWorker on any failure.
      *
-     * @param isSpare true if this is a spare thread
      * @return true if successful
      */
-    private boolean createWorker(boolean isSpare) {
+    private boolean createWorker() {
         ForkJoinWorkerThreadFactory fac = factory;
         Throwable ex = null;
         ForkJoinWorkerThread wt = null;
-        WorkQueue q;
         try {
             if (fac != null && (wt = fac.newThread(this)) != null) {
-                if (isSpare && (q = wt.workQueue) != null)
-                    q.config |= SPARE_WORKER;
                 wt.start();
                 return true;
             }
@@ -1566,10 +1312,10 @@
      */
     private void tryAddWorker(long c) {
         do {
-            long nc = ((AC_MASK & (c + AC_UNIT)) |
+            long nc = ((RC_MASK & (c + RC_UNIT)) |
                        (TC_MASK & (c + TC_UNIT)));
-            if (ctl == c && U.compareAndSwapLong(this, CTL, c, nc)) {
-                createWorker(false);
+            if (ctl == c && CTL.compareAndSet(this, c, nc)) {
+                createWorker();
                 break;
             }
         } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
@@ -1584,41 +1330,57 @@
      */
     final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
         UncaughtExceptionHandler handler;
-        AuxState aux;
-        wt.setDaemon(true);                           // configure thread
+        wt.setDaemon(true);                             // configure thread
         if ((handler = ueh) != null)
             wt.setUncaughtExceptionHandler(handler);
         WorkQueue w = new WorkQueue(this, wt);
-        int i = 0;                                    // assign a pool index
-        int mode = config & MODE_MASK;
-        if ((aux = auxState) != null) {
-            aux.lock();
-            try {
-                int s = (int)(aux.indexSeed += SEED_INCREMENT), n, m;
-                WorkQueue[] ws = workQueues;
-                if (ws != null && (n = ws.length) > 0) {
-                    i = (m = n - 1) & ((s << 1) | 1); // odd-numbered indices
-                    if (ws[i] != null) {              // collision
-                        int probes = 0;               // step by approx half n
-                        int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
-                        while (ws[i = (i + step) & m] != null) {
-                            if (++probes >= n) {
-                                workQueues = ws = Arrays.copyOf(ws, n <<= 1);
-                                m = n - 1;
-                                probes = 0;
-                            }
+        int tid = 0;                                    // for thread name
+        int fifo = mode & FIFO;
+        String prefix = workerNamePrefix;
+        if (prefix != null) {
+            synchronized (prefix) {
+                WorkQueue[] ws = workQueues; int n;
+                int s = indexSeed += SEED_INCREMENT;
+                if (ws != null && (n = ws.length) > 1) {
+                    int m = n - 1;
+                    tid = s & m;
+                    int i = m & ((s << 1) | 1);         // odd-numbered indices
+                    for (int probes = n >>> 1;;) {      // find empty slot
+                        WorkQueue q;
+                        if ((q = ws[i]) == null || q.phase == QUIET)
+                            break;
+                        else if (--probes == 0) {
+                            i = n | 1;                  // resize below
+                            break;
                         }
+                        else
+                            i = (i + 2) & m;
                     }
-                    w.hint = s;                       // use as random seed
-                    w.config = i | mode;
-                    w.scanState = i | (s & 0x7fff0000); // random seq bits
-                    ws[i] = w;
+
+                    int id = i | fifo | (s & ~(SMASK | FIFO | DORMANT));
+                    w.phase = w.id = id;                // now publishable
+
+                    if (i < n)
+                        ws[i] = w;
+                    else {                              // expand array
+                        int an = n << 1;
+                        WorkQueue[] as = new WorkQueue[an];
+                        as[i] = w;
+                        int am = an - 1;
+                        for (int j = 0; j < n; ++j) {
+                            WorkQueue v;                // copy external queue
+                            if ((v = ws[j]) != null)    // position may change
+                                as[v.id & am & SQMASK] = v;
+                            if (++j >= n)
+                                break;
+                            as[j] = ws[j];              // copy worker
+                        }
+                        workQueues = as;
+                    }
                 }
-            } finally {
-                aux.unlock();
             }
+            wt.setName(prefix.concat(Integer.toString(tid)));
         }
-        wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
         return w;
     }
 
@@ -1633,64 +1395,48 @@
      */
     final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
         WorkQueue w = null;
+        int phase = 0;
         if (wt != null && (w = wt.workQueue) != null) {
-            AuxState aux; WorkQueue[] ws;          // remove index from array
-            int idx = w.config & SMASK;
-            int ns = w.nsteals;
-            if ((aux = auxState) != null) {
-                aux.lock();
-                try {
+            Object lock = workerNamePrefix;
+            long ns = (long)w.nsteals & 0xffffffffL;
+            int idx = w.id & SMASK;
+            if (lock != null) {
+                WorkQueue[] ws;                       // remove index from array
+                synchronized (lock) {
                     if ((ws = workQueues) != null && ws.length > idx &&
                         ws[idx] == w)
                         ws[idx] = null;
-                    aux.stealCount += ns;
-                } finally {
-                    aux.unlock();
+                    stealCount += ns;
                 }
             }
-        }
-        if (w == null || (w.config & UNREGISTERED) == 0) { // else pre-adjusted
-            long c;                                   // decrement counts
-            do {} while (!U.compareAndSwapLong
-                         (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
-                                               (TC_MASK & (c - TC_UNIT)) |
-                                               (SP_MASK & c))));
-        }
-        if (w != null) {
-            w.currentSteal = null;
-            w.qlock = -1;                             // ensure set
-            w.cancelAll();                            // cancel remaining tasks
+            phase = w.phase;
         }
-        while (tryTerminate(false, false) >= 0) {     // possibly replace
-            WorkQueue[] ws; int wl, sp; long c;
-            if (w == null || w.array == null ||
-                (ws = workQueues) == null || (wl = ws.length) <= 0)
-                break;
-            else if ((sp = (int)(c = ctl)) != 0) {    // wake up replacement
-                if (tryRelease(c, ws[(wl - 1) & sp], AC_UNIT))
-                    break;
-            }
-            else if (ex != null && (c & ADD_WORKER) != 0L) {
-                tryAddWorker(c);                      // create replacement
-                break;
-            }
-            else                                      // don't need replacement
-                break;
+        if (phase != QUIET) {                         // else pre-adjusted
+            long c;                                   // decrement counts
+            do {} while (!CTL.weakCompareAndSetVolatile
+                         (this, c = ctl, ((RC_MASK & (c - RC_UNIT)) |
+                                          (TC_MASK & (c - TC_UNIT)) |
+                                          (SP_MASK & c))));
         }
+        if (w != null)
+            w.cancelAll();                            // cancel remaining tasks
+
+        if (!tryTerminate(false, false) &&            // possibly replace worker
+            w != null && w.array != null)             // avoid repeated failures
+            signalWork();
+
         if (ex == null)                               // help clean on way out
             ForkJoinTask.helpExpungeStaleExceptions();
         else                                          // rethrow
             ForkJoinTask.rethrow(ex);
     }
 
-    // Signalling
-
     /**
-     * Tries to create or activate a worker if too few are active.
+     * Tries to create or release a worker if too few are running.
      */
     final void signalWork() {
         for (;;) {
-            long c; int sp, i; WorkQueue v; WorkQueue[] ws;
+            long c; int sp; WorkQueue[] ws; int i; WorkQueue v;
             if ((c = ctl) >= 0L)                      // enough workers
                 break;
             else if ((sp = (int)c) == 0) {            // no idle workers
@@ -1705,12 +1451,14 @@
             else if ((v = ws[i]) == null)
                 break;                                // terminating
             else {
-                int ns = sp & ~UNSIGNALLED;
-                int vs = v.scanState;
-                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
-                if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
-                    v.scanState = ns;
-                    LockSupport.unpark(v.parker);
+                int np = sp & ~UNSIGNALLED;
+                int vp = v.phase;
+                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + RC_UNIT));
+                Thread vt = v.owner;
+                if (sp == vp && CTL.compareAndSet(this, c, nc)) {
+                    v.phase = np;
+                    if (v.source < 0)
+                        LockSupport.unpark(vt);
                     break;
                 }
             }
@@ -1718,442 +1466,183 @@
     }
 
     /**
-     * Signals and releases worker v if it is top of idle worker
-     * stack.  This performs a one-shot version of signalWork only if
-     * there is (apparently) at least one idle worker.
+     * Tries to decrement counts (sometimes implicitly) and possibly
+     * arrange for a compensating worker in preparation for blocking:
+     * If not all core workers yet exist, creates one, else if any are
+     * unreleased (possibly including caller) releases one, else if
+     * fewer than the minimum allowed number of workers running,
+     * checks to see that they are all active, and if so creates an
+     * extra worker unless over maximum limit and policy is to
+     * saturate.  Most of these steps can fail due to interference, in
+     * which case 0 is returned so caller will retry. A negative
+     * return value indicates that the caller doesn't need to
+     * re-adjust counts when later unblocked.
      *
-     * @param c incoming ctl value
-     * @param v if non-null, a worker
-     * @param inc the increment to active count (zero when compensating)
-     * @return true if successful
-     */
-    private boolean tryRelease(long c, WorkQueue v, long inc) {
-        int sp = (int)c, ns = sp & ~UNSIGNALLED;
-        if (v != null) {
-            int vs = v.scanState;
-            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + inc));
-            if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
-                v.scanState = ns;
-                LockSupport.unpark(v.parker);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * With approx probability of a missed signal, tries (once) to
-     * reactivate worker w (or some other worker), failing if stale or
-     * known to be already active.
-     *
-     * @param w the worker
-     * @param ws the workQueue array to use
-     * @param r random seed
-     */
-    private void tryReactivate(WorkQueue w, WorkQueue[] ws, int r) {
-        long c; int sp, wl; WorkQueue v;
-        if ((sp = (int)(c = ctl)) != 0 && w != null &&
-            ws != null && (wl = ws.length) > 0 &&
-            ((sp ^ r) & SS_SEQ) == 0 &&
-            (v = ws[(wl - 1) & sp]) != null) {
-            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
-            int ns = sp & ~UNSIGNALLED;
-            if (w.scanState < 0 &&
-                v.scanState == sp &&
-                U.compareAndSwapLong(this, CTL, c, nc)) {
-                v.scanState = ns;
-                LockSupport.unpark(v.parker);
-            }
-        }
-    }
-
-    /**
-     * If worker w exists and is active, enqueues and sets status to inactive.
-     *
-     * @param w the worker
-     * @param ss current (non-negative) scanState
+     * @return 1: block then adjust, -1: block without adjust, 0 : retry
      */
-    private void inactivate(WorkQueue w, int ss) {
-        int ns = (ss + SS_SEQ) | UNSIGNALLED;
-        long lc = ns & SP_MASK, nc, c;
-        if (w != null) {
-            w.scanState = ns;
-            do {
-                nc = lc | (UC_MASK & ((c = ctl) - AC_UNIT));
-                w.stackPred = (int)c;
-            } while (!U.compareAndSwapLong(this, CTL, c, nc));
-        }
-    }
-
-    /**
-     * Possibly blocks worker w waiting for signal, or returns
-     * negative status if the worker should terminate. May return
-     * without status change if multiple stale unparks and/or
-     * interrupts occur.
-     *
-     * @param w the calling worker
-     * @return negative if w should terminate
-     */
-    private int awaitWork(WorkQueue w) {
-        int stat = 0;
-        if (w != null && w.scanState < 0) {
-            long c = ctl;
-            if ((int)(c >> AC_SHIFT) + (config & SMASK) <= 0)
-                stat = timedAwaitWork(w, c);     // possibly quiescent
-            else if ((runState & STOP) != 0)
-                stat = w.qlock = -1;             // pool terminating
-            else if (w.scanState < 0) {
-                w.parker = Thread.currentThread();
-                if (w.scanState < 0)             // recheck after write
-                    LockSupport.park(this);
-                w.parker = null;
-                if ((runState & STOP) != 0)
-                    stat = w.qlock = -1;         // recheck
-                else if (w.scanState < 0)
-                    Thread.interrupted();        // clear status
+    private int tryCompensate(WorkQueue w) {
+        int t, n, sp;
+        long c = ctl;
+        WorkQueue[] ws = workQueues;
+        if ((t = (short)(c >>> TC_SHIFT)) >= 0) {
+            if (ws == null || (n = ws.length) <= 0 || w == null)
+                return 0;                        // disabled
+            else if ((sp = (int)c) != 0) {       // replace or release
+                WorkQueue v = ws[sp & (n - 1)];
+                int wp = w.phase;
+                long uc = UC_MASK & ((wp < 0) ? c + RC_UNIT : c);
+                int np = sp & ~UNSIGNALLED;
+                if (v != null) {
+                    int vp = v.phase;
+                    Thread vt = v.owner;
+                    long nc = ((long)v.stackPred & SP_MASK) | uc;
+                    if (vp == sp && CTL.compareAndSet(this, c, nc)) {
+                        v.phase = np;
+                        if (v.source < 0)
+                            LockSupport.unpark(vt);
+                        return (wp < 0) ? -1 : 1;
+                    }
+                }
+                return 0;
+            }
+            else if ((int)(c >> RC_SHIFT) -      // reduce parallelism
+                     (short)(bounds & SMASK) > 0) {
+                long nc = ((RC_MASK & (c - RC_UNIT)) | (~RC_MASK & c));
+                return CTL.compareAndSet(this, c, nc) ? 1 : 0;
             }
-        }
-        return stat;
-    }
-
-    /**
-     * Possibly triggers shutdown and tries (once) to block worker
-     * when pool is (or may be) quiescent. Waits up to a duration
-     * determined by number of workers.  On timeout, if ctl has not
-     * changed, terminates the worker, which will in turn wake up
-     * another worker to possibly repeat this process.
-     *
-     * @param w the calling worker
-     * @return negative if w should terminate
-     */
-    private int timedAwaitWork(WorkQueue w, long c) {
-        int stat = 0;
-        int scale = 1 - (short)(c >>> TC_SHIFT);
-        long deadline = (((scale <= 0) ? 1 : scale) * IDLE_TIMEOUT_MS +
-                         System.currentTimeMillis());
-        if ((runState >= 0 || (stat = tryTerminate(false, false)) > 0) &&
-            w != null && w.scanState < 0) {
-            int ss; AuxState aux;
-            w.parker = Thread.currentThread();
-            if (w.scanState < 0)
-                LockSupport.parkUntil(this, deadline);
-            w.parker = null;
-            if ((runState & STOP) != 0)
-                stat = w.qlock = -1;         // pool terminating
-            else if ((ss = w.scanState) < 0 && !Thread.interrupted() &&
-                     (int)c == ss && (aux = auxState) != null && ctl == c &&
-                     deadline - System.currentTimeMillis() <= TIMEOUT_SLOP_MS) {
-                aux.lock();
-                try {                        // pre-deregister
-                    WorkQueue[] ws;
-                    int cfg = w.config, idx = cfg & SMASK;
-                    long nc = ((UC_MASK & (c - TC_UNIT)) |
-                               (SP_MASK & w.stackPred));
-                    if ((runState & STOP) == 0 &&
-                        (ws = workQueues) != null &&
-                        idx < ws.length && idx >= 0 && ws[idx] == w &&
-                        U.compareAndSwapLong(this, CTL, c, nc)) {
-                        ws[idx] = null;
-                        w.config = cfg | UNREGISTERED;
-                        stat = w.qlock = -1;
+            else {                               // validate
+                int md = mode, pc = md & SMASK, tc = pc + t, bc = 0;
+                boolean unstable = false;
+                for (int i = 1; i < n; i += 2) {
+                    WorkQueue q; Thread wt; Thread.State ts;
+                    if ((q = ws[i]) != null) {
+                        if (q.source == 0) {
+                            unstable = true;
+                            break;
+                        }
+                        else {
+                            --tc;
+                            if ((wt = q.owner) != null &&
+                                ((ts = wt.getState()) == Thread.State.BLOCKED ||
+                                 ts == Thread.State.WAITING))
+                                ++bc;            // worker is blocking
+                        }
                     }
-                } finally {
-                    aux.unlock();
+                }
+                if (unstable || tc != 0 || ctl != c)
+                    return 0;                    // inconsistent
+                else if (t + pc >= MAX_CAP || t >= (bounds >>> SWIDTH)) {
+                    Predicate<? super ForkJoinPool> sat;
+                    if ((sat = saturate) != null && sat.test(this))
+                        return -1;
+                    else if (bc < pc) {          // lagging
+                        Thread.yield();          // for retry spins
+                        return 0;
+                    }
+                    else
+                        throw new RejectedExecutionException(
+                            "Thread limit exceeded replacing blocked worker");
                 }
             }
         }
-        return stat;
-    }
 
-    /**
-     * If the given worker is a spare with no queued tasks, and there
-     * are enough existing workers, drops it from ctl counts and sets
-     * its state to terminated.
-     *
-     * @param w the calling worker -- must be a spare
-     * @return true if dropped (in which case it must not process more tasks)
-     */
-    private boolean tryDropSpare(WorkQueue w) {
-        if (w != null && w.isEmpty()) {           // no local tasks
-            long c; int sp, wl; WorkQueue[] ws; WorkQueue v;
-            while ((short)((c = ctl) >> TC_SHIFT) > 0 &&
-                   ((sp = (int)c) != 0 || (int)(c >> AC_SHIFT) > 0) &&
-                   (ws = workQueues) != null && (wl = ws.length) > 0) {
-                boolean dropped, canDrop;
-                if (sp == 0) {                    // no queued workers
-                    long nc = ((AC_MASK & (c - AC_UNIT)) |
-                               (TC_MASK & (c - TC_UNIT)) | (SP_MASK & c));
-                    dropped = U.compareAndSwapLong(this, CTL, c, nc);
-                }
-                else if (
-                    (v = ws[(wl - 1) & sp]) == null || v.scanState != sp)
-                    dropped = false;              // stale; retry
-                else {
-                    long nc = v.stackPred & SP_MASK;
-                    if (w == v || w.scanState >= 0) {
-                        canDrop = true;           // w unqueued or topmost
-                        nc |= ((AC_MASK & c) |    // ensure replacement
-                               (TC_MASK & (c - TC_UNIT)));
-                    }
-                    else {                        // w may be queued
-                        canDrop = false;          // help uncover
-                        nc |= ((AC_MASK & (c + AC_UNIT)) |
-                               (TC_MASK & c));
-                    }
-                    if (U.compareAndSwapLong(this, CTL, c, nc)) {
-                        v.scanState = sp & ~UNSIGNALLED;
-                        LockSupport.unpark(v.parker);
-                        dropped = canDrop;
-                    }
-                    else
-                        dropped = false;
-                }
-                if (dropped) {                    // pre-deregister
-                    int cfg = w.config, idx = cfg & SMASK;
-                    if (idx >= 0 && idx < ws.length && ws[idx] == w)
-                        ws[idx] = null;
-                    w.config = cfg | UNREGISTERED;
-                    w.qlock = -1;
-                    return true;
-                }
-            }
-        }
-        return false;
+        long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); // expand pool
+        return CTL.compareAndSet(this, c, nc) && createWorker() ? 1 : 0;
     }
 
     /**
      * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
+     * See above for explanation.
      */
     final void runWorker(WorkQueue w) {
+        WorkQueue[] ws;
         w.growArray();                                  // allocate queue
-        int bound = (w.config & SPARE_WORKER) != 0 ? 0 : POLL_LIMIT;
-        long seed = w.hint * 0xdaba0b6eb09322e3L;       // initial random seed
-        if ((runState & STOP) == 0) {
-            for (long r = (seed == 0L) ? 1L : seed;;) { // ensure nonzero
-                if (bound == 0 && tryDropSpare(w))
-                    break;
-                // high bits of prev seed for step; current low bits for idx
-                int step = (int)(r >>> 48) | 1;
-                r ^= r >>> 12; r ^= r << 25; r ^= r >>> 27; // xorshift
-                if (scan(w, bound, step, (int)r) < 0 && awaitWork(w) < 0)
-                    break;
-            }
-        }
-    }
-
-    // Scanning for tasks
-
-    /**
-     * Repeatedly scans for and tries to steal and execute (via
-     * workQueue.runTask) a queued task. Each scan traverses queues in
-     * pseudorandom permutation. Upon finding a non-empty queue, makes
-     * at most the given bound attempts to re-poll (fewer if
-     * contended) on the same queue before returning (impossible
-     * scanState value) 0 to restart scan. Else returns after at least
-     * 1 and at most 32 full scans.
-     *
-     * @param w the worker (via its WorkQueue)
-     * @param bound repoll bound as bitmask (0 if spare)
-     * @param step (circular) index increment per iteration (must be odd)
-     * @param r a random seed for origin index
-     * @return negative if should await signal
-     */
-    private int scan(WorkQueue w, int bound, int step, int r) {
-        int stat = 0, wl; WorkQueue[] ws;
-        if ((ws = workQueues) != null && w != null && (wl = ws.length) > 0) {
-            for (int m = wl - 1,
-                     origin = m & r, idx = origin,
-                     npolls = 0,
-                     ss = w.scanState;;) {         // negative if inactive
-                WorkQueue q; ForkJoinTask<?>[] a; int b, al;
-                if ((q = ws[idx]) != null && (b = q.base) - q.top < 0 &&
+        int r = w.id ^ ThreadLocalRandom.nextSecondarySeed();
+        if (r == 0)                                     // initial nonzero seed
+            r = 1;
+        int lastSignalId = 0;                           // avoid unneeded signals
+        while ((ws = workQueues) != null) {
+            boolean nonempty = false;                   // scan
+            for (int n = ws.length, j = n, m = n - 1; j > 0; --j) {
+                WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
+                if ((i = r & m) >= 0 && i < n &&        // always true
+                    (q = ws[i]) != null && (b = q.base) - q.top < 0 &&
                     (a = q.array) != null && (al = a.length) > 0) {
+                    int qid = q.id;                     // (never zero)
                     int index = (al - 1) & b;
-                    long offset = ((long)index << ASHIFT) + ABASE;
                     ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        U.getObjectVolatile(a, offset);
-                    if (t == null)
-                        break;                     // empty or busy
-                    else if (b++ != q.base)
-                        break;                     // busy
-                    else if (ss < 0) {
-                        tryReactivate(w, ws, r);
-                        break;                     // retry upon rescan
-                    }
-                    else if (!U.compareAndSwapObject(a, offset, t, null))
-                        break;                     // contended
-                    else {
-                        q.base = b;
-                        w.currentSteal = t;
-                        if (b != q.top)            // propagate signal
-                            signalWork();
-                        w.runTask(t);
-                        if (++npolls > bound)
-                            break;
+                        QA.getAcquire(a, index);
+                    if (t != null && b++ == q.base &&
+                        QA.compareAndSet(a, index, t, null)) {
+                        if ((q.base = b) - q.top < 0 && qid != lastSignalId)
+                            signalWork();               // propagate signal
+                        w.source = lastSignalId = qid;
+                        t.doExec();
+                        if ((w.id & FIFO) != 0)         // run remaining locals
+                            w.localPollAndExec(POLL_LIMIT);
+                        else
+                            w.localPopAndExec(POLL_LIMIT);
+                        ForkJoinWorkerThread thread = w.owner;
+                        ++w.nsteals;
+                        w.source = 0;                   // now idle
+                        if (thread != null)
+                            thread.afterTopLevelExec();
                     }
+                    nonempty = true;
                 }
-                else if (npolls != 0)              // rescan
+                else if (nonempty)
                     break;
-                else if ((idx = (idx + step) & m) == origin) {
-                    if (ss < 0) {                  // await signal
-                        stat = ss;
-                        break;
-                    }
-                    else if (r >= 0) {
-                        inactivate(w, ss);
-                        break;
-                    }
-                    else
-                        r <<= 1;                   // at most 31 rescans
-                }
+                else
+                    ++r;
             }
-        }
-        return stat;
-    }
-
-    // Joining tasks
 
-    /**
-     * Tries to steal and run tasks within the target's computation.
-     * Uses a variant of the top-level algorithm, restricted to tasks
-     * with the given task as ancestor: It prefers taking and running
-     * eligible tasks popped from the worker's own queue (via
-     * popCC). Otherwise it scans others, randomly moving on
-     * contention or execution, deciding to give up based on a
-     * checksum (via return codes from pollAndExecCC). The maxTasks
-     * argument supports external usages; internal calls use zero,
-     * allowing unbounded steps (external calls trap non-positive
-     * values).
-     *
-     * @param w caller
-     * @param maxTasks if non-zero, the maximum number of other tasks to run
-     * @return task status on exit
-     */
-    final int helpComplete(WorkQueue w, CountedCompleter<?> task,
-                           int maxTasks) {
-        WorkQueue[] ws; int s = 0, wl;
-        if ((ws = workQueues) != null && (wl = ws.length) > 1 &&
-            task != null && w != null) {
-            for (int m = wl - 1,
-                     mode = w.config,
-                     r = ~mode,                  // scanning seed
-                     origin = r & m, k = origin, // first queue to scan
-                     step = 3,                   // first scan step
-                     h = 1,                      // 1:ran, >1:contended, <0:hash
-                     oldSum = 0, checkSum = 0;;) {
-                CountedCompleter<?> p; WorkQueue q; int i;
-                if ((s = task.status) < 0)
-                    break;
-                if (h == 1 && (p = w.popCC(task, mode)) != null) {
-                    p.doExec();                  // run local task
-                    if (maxTasks != 0 && --maxTasks == 0)
-                        break;
-                    origin = k;                  // reset
-                    oldSum = checkSum = 0;
-                }
-                else {                           // poll other worker queues
-                    if ((i = k | 1) < 0 || i > m || (q = ws[i]) == null)
-                        h = 0;
-                    else if ((h = q.pollAndExecCC(task)) < 0)
-                        checkSum += h;
-                    if (h > 0) {
-                        if (h == 1 && maxTasks != 0 && --maxTasks == 0)
-                            break;
-                        step = (r >>> 16) | 3;
-                        r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
-                        k = origin = r & m;      // move and restart
-                        oldSum = checkSum = 0;
-                    }
-                    else if ((k = (k + step) & m) == origin) {
-                        if (oldSum == (oldSum = checkSum))
-                            break;
-                        checkSum = 0;
-                    }
-                }
+            if (nonempty) {                             // move (xorshift)
+                r ^= r << 13; r ^= r >>> 17; r ^= r << 5;
             }
-        }
-        return s;
-    }
-
-    /**
-     * Tries to locate and execute tasks for a stealer of the given
-     * task, or in turn one of its stealers. Traces currentSteal ->
-     * currentJoin links looking for a thread working on a descendant
-     * of the given task and with a non-empty queue to steal back and
-     * execute tasks from. The first call to this method upon a
-     * waiting join will often entail scanning/search, (which is OK
-     * because the joiner has nothing better to do), but this method
-     * leaves hints in workers to speed up subsequent calls.
-     *
-     * @param w caller
-     * @param task the task to join
-     */
-    private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
-        if (task != null && w != null) {
-            ForkJoinTask<?> ps = w.currentSteal;
-            WorkQueue[] ws; int wl, oldSum = 0;
-            outer: while (w.tryRemoveAndExec(task) && task.status >= 0 &&
-                          (ws = workQueues) != null && (wl = ws.length) > 0) {
-                ForkJoinTask<?> subtask;
-                int m = wl - 1, checkSum = 0;          // for stability check
-                WorkQueue j = w, v;                    // v is subtask stealer
-                descent: for (subtask = task; subtask.status >= 0; ) {
-                    for (int h = j.hint | 1, k = 0, i;;) {
-                        if ((v = ws[i = (h + (k << 1)) & m]) != null) {
-                            if (v.currentSteal == subtask) {
-                                j.hint = i;
-                                break;
-                            }
-                            checkSum += v.base;
+            else {
+                int phase;
+                lastSignalId = 0;                       // clear for next scan
+                if ((phase = w.phase) >= 0) {           // enqueue
+                    int np = w.phase = (phase + SS_SEQ) | UNSIGNALLED;
+                    long c, nc;
+                    do {
+                        w.stackPred = (int)(c = ctl);
+                        nc = ((c - RC_UNIT) & UC_MASK) | (SP_MASK & np);
+                    } while (!CTL.weakCompareAndSetVolatile(this, c, nc));
+                }
+                else {                                  // already queued
+                    int pred = w.stackPred;
+                    w.source = DORMANT;                 // enable signal
+                    for (int steps = 0;;) {
+                        int md, rc; long c;
+                        if (w.phase >= 0) {
+                            w.source = 0;
+                            break;
                         }
-                        if (++k > m)                   // can't find stealer
-                            break outer;
-                    }
-
-                    for (;;) {                         // help v or descend
-                        ForkJoinTask<?>[] a; int b, al;
-                        if (subtask.status < 0)        // too late to help
-                            break descent;
-                        checkSum += (b = v.base);
-                        ForkJoinTask<?> next = v.currentJoin;
-                        ForkJoinTask<?> t = null;
-                        if ((a = v.array) != null && (al = a.length) > 0) {
-                            int index = (al - 1) & b;
-                            long offset = ((long)index << ASHIFT) + ABASE;
-                            t = (ForkJoinTask<?>)
-                                U.getObjectVolatile(a, offset);
-                            if (t != null && b++ == v.base) {
-                                if (j.currentJoin != subtask ||
-                                    v.currentSteal != subtask ||
-                                    subtask.status < 0)
-                                    break descent;     // stale
-                                if (U.compareAndSwapObject(a, offset, t, null)) {
-                                    v.base = b;
-                                    w.currentSteal = t;
-                                    for (int top = w.top;;) {
-                                        t.doExec();    // help
-                                        w.currentSteal = ps;
-                                        if (task.status < 0)
-                                            break outer;
-                                        if (w.top == top)
-                                            break;     // run local tasks
-                                        if ((t = w.pop()) == null)
-                                            break descent;
-                                        w.currentSteal = t;
-                                    }
+                        else if ((md = mode) < 0)       // shutting down
+                            return;
+                        else if ((rc = ((md & SMASK) +  // possibly quiescent
+                                        (int)((c = ctl) >> RC_SHIFT))) <= 0 &&
+                                 (md & SHUTDOWN) != 0 &&
+                                 tryTerminate(false, false))
+                            return;                     // help terminate
+                        else if ((++steps & 1) == 0)
+                            Thread.interrupted();       // clear between parks
+                        else if (rc <= 0 && pred != 0 && phase == (int)c) {
+                            long d = keepAlive + System.currentTimeMillis();
+                            LockSupport.parkUntil(this, d);
+                            if (ctl == c &&
+                                d - System.currentTimeMillis() <= TIMEOUT_SLOP) {
+                                long nc = ((UC_MASK & (c - TC_UNIT)) |
+                                           (SP_MASK & pred));
+                                if (CTL.compareAndSet(this, c, nc)) {
+                                    w.phase = QUIET;
+                                    return;             // drop on timeout
                                 }
                             }
                         }
-                        if (t == null && b == v.base && b - v.top >= 0) {
-                            if ((subtask = next) == null) {  // try to descend
-                                if (next == v.currentJoin &&
-                                    oldSum == (oldSum = checkSum))
-                                    break outer;
-                                break descent;
-                            }
-                            j = v;
-                            break;
-                        }
+                        else
+                            LockSupport.park(this);
                     }
                 }
             }
@@ -2161,59 +1650,10 @@
     }
 
     /**
-     * Tries to decrement active count (sometimes implicitly) and
-     * possibly release or create a compensating worker in preparation
-     * for blocking. Returns false (retryable by caller), on
-     * contention, detected staleness, instability, or termination.
-     *
-     * @param w caller
-     */
-    private boolean tryCompensate(WorkQueue w) {
-        boolean canBlock; int wl;
-        long c = ctl;
-        WorkQueue[] ws = workQueues;
-        int pc = config & SMASK;
-        int ac = pc + (int)(c >> AC_SHIFT);
-        int tc = pc + (short)(c >> TC_SHIFT);
-        if (w == null || w.qlock < 0 || pc == 0 ||  // terminating or disabled
-            ws == null || (wl = ws.length) <= 0)
-            canBlock = false;
-        else {
-            int m = wl - 1, sp;
-            boolean busy = true;                    // validate ac
-            for (int i = 0; i <= m; ++i) {
-                int k; WorkQueue v;
-                if ((k = (i << 1) | 1) <= m && k >= 0 && (v = ws[k]) != null &&
-                    v.scanState >= 0 && v.currentSteal == null) {
-                    busy = false;
-                    break;
-                }
-            }
-            if (!busy || ctl != c)
-                canBlock = false;                   // unstable or stale
-            else if ((sp = (int)c) != 0)            // release idle worker
-                canBlock = tryRelease(c, ws[m & sp], 0L);
-            else if (tc >= pc && ac > 1 && w.isEmpty()) {
-                long nc = ((AC_MASK & (c - AC_UNIT)) |
-                           (~AC_MASK & c));         // uncompensated
-                canBlock = U.compareAndSwapLong(this, CTL, c, nc);
-            }
-            else if (tc >= MAX_CAP ||
-                     (this == common && tc >= pc + COMMON_MAX_SPARES))
-                throw new RejectedExecutionException(
-                    "Thread limit exceeded replacing blocked worker");
-            else {                                  // similar to tryAddWorker
-                boolean isSpare = (tc >= pc);
-                long nc = (AC_MASK & c) | (TC_MASK & (c + TC_UNIT));
-                canBlock = (U.compareAndSwapLong(this, CTL, c, nc) &&
-                            createWorker(isSpare)); // throws on exception
-            }
-        }
-        return canBlock;
-    }
-
-    /**
      * Helps and/or blocks until the given task is done or timeout.
+     * First tries locally helping, then scans other queues for a task
+     * produced by one of w's stealers; compensating and blocking if
+     * none are found (rescanning if tryCompensate fails).
      *
      * @param w caller
      * @param task the task
@@ -2222,61 +1662,166 @@
      */
     final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
         int s = 0;
-        if (w != null) {
-            ForkJoinTask<?> prevJoin = w.currentJoin;
-            if (task != null && (s = task.status) >= 0) {
-                w.currentJoin = task;
-                CountedCompleter<?> cc = (task instanceof CountedCompleter) ?
-                    (CountedCompleter<?>)task : null;
-                for (;;) {
-                    if (cc != null)
-                        helpComplete(w, cc, 0);
-                    else
-                        helpStealer(w, task);
-                    if ((s = task.status) < 0)
-                        break;
-                    long ms, ns;
+        if (w != null && task != null &&
+            (!(task instanceof CountedCompleter) ||
+             (s = w.localHelpCC((CountedCompleter<?>)task, 0)) >= 0)) {
+            w.tryRemoveAndExec(task);
+            int src = w.source, id = w.id;
+            s = task.status;
+            while (s >= 0) {
+                WorkQueue[] ws;
+                boolean nonempty = false;
+                int r = ThreadLocalRandom.nextSecondarySeed() | 1; // odd indices
+                if ((ws = workQueues) != null) {       // scan for matching id
+                    for (int n = ws.length, m = n - 1, j = -n; j < n; j += 2) {
+                        WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
+                        if ((i = (r + j) & m) >= 0 && i < n &&
+                            (q = ws[i]) != null && q.source == id &&
+                            (b = q.base) - q.top < 0 &&
+                            (a = q.array) != null && (al = a.length) > 0) {
+                            int qid = q.id;
+                            int index = (al - 1) & b;
+                            ForkJoinTask<?> t = (ForkJoinTask<?>)
+                                QA.getAcquire(a, index);
+                            if (t != null && b++ == q.base && id == q.source &&
+                                QA.compareAndSet(a, index, t, null)) {
+                                q.base = b;
+                                w.source = qid;
+                                t.doExec();
+                                w.source = src;
+                            }
+                            nonempty = true;
+                            break;
+                        }
+                    }
+                }
+                if ((s = task.status) < 0)
+                    break;
+                else if (!nonempty) {
+                    long ms, ns; int block;
                     if (deadline == 0L)
-                        ms = 0L;
+                        ms = 0L;                       // untimed
                     else if ((ns = deadline - System.nanoTime()) <= 0L)
-                        break;
+                        break;                         // timeout
                     else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
-                        ms = 1L;
-                    if (tryCompensate(w)) {
+                        ms = 1L;                       // avoid 0 for timed wait
+                    if ((block = tryCompensate(w)) != 0) {
                         task.internalWait(ms);
-                        U.getAndAddLong(this, CTL, AC_UNIT);
+                        CTL.getAndAdd(this, (block > 0) ? RC_UNIT : 0L);
                     }
-                    if ((s = task.status) < 0)
-                        break;
+                    s = task.status;
                 }
-                w.currentJoin = prevJoin;
             }
         }
         return s;
     }
 
-    // Specialized scanning
+    /**
+     * Runs tasks until {@code isQuiescent()}. Rather than blocking
+     * when tasks cannot be found, rescans until all others cannot
+     * find tasks either.
+     */
+    final void helpQuiescePool(WorkQueue w) {
+        int prevSrc = w.source, fifo = w.id & FIFO;
+        for (int source = prevSrc, released = -1;;) { // -1 until known
+            WorkQueue[] ws;
+            if (fifo != 0)
+                w.localPollAndExec(0);
+            else
+                w.localPopAndExec(0);
+            if (released == -1 && w.phase >= 0)
+                released = 1;
+            boolean quiet = true, empty = true;
+            int r = ThreadLocalRandom.nextSecondarySeed();
+            if ((ws = workQueues) != null) {
+                for (int n = ws.length, j = n, m = n - 1; j > 0; --j) {
+                    WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
+                    if ((i = (r - j) & m) >= 0 && i < n && (q = ws[i]) != null) {
+                        if ((b = q.base) - q.top < 0 &&
+                            (a = q.array) != null && (al = a.length) > 0) {
+                            int qid = q.id;
+                            if (released == 0) {    // increment
+                                released = 1;
+                                CTL.getAndAdd(this, RC_UNIT);
+                            }
+                            int index = (al - 1) & b;
+                            ForkJoinTask<?> t = (ForkJoinTask<?>)
+                                QA.getAcquire(a, index);
+                            if (t != null && b++ == q.base &&
+                                QA.compareAndSet(a, index, t, null)) {
+                                q.base = b;
+                                w.source = source = q.id;
+                                t.doExec();
+                                w.source = source = prevSrc;
+                            }
+                            quiet = empty = false;
+                            break;
+                        }
+                        else if ((q.source & QUIET) == 0)
+                            quiet = false;
+                    }
+                }
+            }
+            if (quiet) {
+                if (released == 0)
+                    CTL.getAndAdd(this, RC_UNIT);
+                w.source = prevSrc;
+                break;
+            }
+            else if (empty) {
+                if (source != QUIET)
+                    w.source = source = QUIET;
+                if (released == 1) {                 // decrement
+                    released = 0;
+                    CTL.getAndAdd(this, RC_MASK & -RC_UNIT);
+                }
+            }
+        }
+    }
 
     /**
-     * Returns a (probably) non-empty steal queue, if one is found
-     * during a scan, else null.  This method must be retried by
-     * caller if, by the time it tries to use the queue, it is empty.
+     * Scans for and returns a polled task, if available.
+     * Used only for untracked polls.
+     *
+     * @param submissionsOnly if true, only scan submission queues
      */
-    private WorkQueue findNonEmptyStealQueue() {
-        WorkQueue[] ws; int wl;  // one-shot version of scan loop
-        int r = ThreadLocalRandom.nextSecondarySeed();
-        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
-            int m = wl - 1, origin = r & m;
+    private ForkJoinTask<?> pollScan(boolean submissionsOnly) {
+        WorkQueue[] ws; int n;
+        rescan: while ((mode & STOP) == 0 && (ws = workQueues) != null &&
+                      (n = ws.length) > 0) {
+            int m = n - 1;
+            int r = ThreadLocalRandom.nextSecondarySeed();
+            int h = r >>> 16;
+            int origin, step;
+            if (submissionsOnly) {
+                origin = (r & ~1) & m;         // even indices and steps
+                step = (h & ~1) | 2;
+            }
+            else {
+                origin = r & m;
+                step = h | 1;
+            }
             for (int k = origin, oldSum = 0, checkSum = 0;;) {
-                WorkQueue q; int b;
+                WorkQueue q; int b, al; ForkJoinTask<?>[] a;
                 if ((q = ws[k]) != null) {
-                    if ((b = q.base) - q.top < 0)
-                        return q;
-                    checkSum += b;
+                    checkSum += b = q.base;
+                    if (b - q.top < 0 &&
+                        (a = q.array) != null && (al = a.length) > 0) {
+                        int index = (al - 1) & b;
+                        ForkJoinTask<?> t = (ForkJoinTask<?>)
+                            QA.getAcquire(a, index);
+                        if (t != null && b++ == q.base &&
+                            QA.compareAndSet(a, index, t, null)) {
+                            q.base = b;
+                            return t;
+                        }
+                        else
+                            break; // restart
+                    }
                 }
-                if ((k = (k + 1) & m) == origin) {
+                if ((k = (k + step) & m) == origin) {
                     if (oldSum == (oldSum = checkSum))
-                        break;
+                        break rescan;
                     checkSum = 0;
                 }
             }
@@ -2285,58 +1830,160 @@
     }
 
     /**
-     * Runs tasks until {@code isQuiescent()}. We piggyback on
-     * active count ctl maintenance, but rather than blocking
-     * when tasks cannot be found, we rescan until all others cannot
-     * find tasks either.
-     */
-    final void helpQuiescePool(WorkQueue w) {
-        ForkJoinTask<?> ps = w.currentSteal; // save context
-        int wc = w.config;
-        for (boolean active = true;;) {
-            long c; WorkQueue q; ForkJoinTask<?> t;
-            if (wc >= 0 && (t = w.pop()) != null) { // run locals if LIFO
-                (w.currentSteal = t).doExec();
-                w.currentSteal = ps;
-            }
-            else if ((q = findNonEmptyStealQueue()) != null) {
-                if (!active) {      // re-establish active count
-                    active = true;
-                    U.getAndAddLong(this, CTL, AC_UNIT);
-                }
-                if ((t = q.pollAt(q.base)) != null) {
-                    (w.currentSteal = t).doExec();
-                    w.currentSteal = ps;
-                    if (++w.nsteals < 0)
-                        w.transferStealCount(this);
-                }
-            }
-            else if (active) {      // decrement active count without queuing
-                long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c);
-                if (U.compareAndSwapLong(this, CTL, c, nc))
-                    active = false;
-            }
-            else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 &&
-                     U.compareAndSwapLong(this, CTL, c, c + AC_UNIT))
-                break;
-        }
-    }
-
-    /**
      * Gets and removes a local or stolen task for the given worker.
      *
      * @return a task, if available
      */
     final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
-        for (ForkJoinTask<?> t;;) {
-            WorkQueue q;
-            if ((t = w.nextLocalTask()) != null)
-                return t;
-            if ((q = findNonEmptyStealQueue()) == null)
-                return null;
-            if ((t = q.pollAt(q.base)) != null)
-                return t;
+        ForkJoinTask<?> t;
+        if (w != null &&
+            (t = (w.id & FIFO) != 0 ? w.poll() : w.pop()) != null)
+            return t;
+        else
+            return pollScan(false);
+    }
+
+    // External operations
+
+    /**
+     * Adds the given task to a submission queue at submitter's
+     * current queue, creating one if null or contended.
+     *
+     * @param task the task. Caller must ensure non-null.
+     */
+    final void externalPush(ForkJoinTask<?> task) {
+        int r;                                // initialize caller's probe
+        if ((r = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();
+            r = ThreadLocalRandom.getProbe();
         }
+        for (;;) {
+            int md = mode, n;
+            WorkQueue[] ws = workQueues;
+            if ((md & SHUTDOWN) != 0 || ws == null || (n = ws.length) <= 0)
+                throw new RejectedExecutionException();
+            else {
+                WorkQueue q;
+                boolean push = false, grow = false;
+                if ((q = ws[(n - 1) & r & SQMASK]) == null) {
+                    Object lock = workerNamePrefix;
+                    int qid = (r | QUIET) & ~(FIFO | OWNED);
+                    q = new WorkQueue(this, null);
+                    q.id = qid;
+                    q.source = QUIET;
+                    q.phase = QLOCK;          // lock queue
+                    if (lock != null) {
+                        synchronized (lock) { // lock pool to install
+                            int i;
+                            if ((ws = workQueues) != null &&
+                                (n = ws.length) > 0 &&
+                                ws[i = qid & (n - 1) & SQMASK] == null) {
+                                ws[i] = q;
+                                push = grow = true;
+                            }
+                        }
+                    }
+                }
+                else if (q.tryLockSharedQueue()) {
+                    int b = q.base, s = q.top, al, d; ForkJoinTask<?>[] a;
+                    if ((a = q.array) != null && (al = a.length) > 0 &&
+                        al - 1 + (d = b - s) > 0) {
+                        a[(al - 1) & s] = task;
+                        q.top = s + 1;        // relaxed writes OK here
+                        q.phase = 0;
+                        if (d < 0 && q.base - s < -1)
+                            break;            // no signal needed
+                    }
+                    else
+                        grow = true;
+                    push = true;
+                }
+                if (push) {
+                    if (grow) {
+                        try {
+                            q.growArray();
+                            int s = q.top, al; ForkJoinTask<?>[] a;
+                            if ((a = q.array) != null && (al = a.length) > 0) {
+                                a[(al - 1) & s] = task;
+                                q.top = s + 1;
+                            }
+                        } finally {
+                            q.phase = 0;
+                        }
+                    }
+                    signalWork();
+                    break;
+                }
+                else                          // move if busy
+                    r = ThreadLocalRandom.advanceProbe(r);
+            }
+        }
+    }
+
+    /**
+     * Pushes a possibly-external submission.
+     */
+    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
+        Thread t; ForkJoinWorkerThread w; WorkQueue q;
+        if (task == null)
+            throw new NullPointerException();
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (w = (ForkJoinWorkerThread)t).pool == this &&
+            (q = w.workQueue) != null)
+            q.push(task);
+        else
+            externalPush(task);
+        return task;
+    }
+
+    /**
+     * Returns common pool queue for an external thread.
+     */
+    static WorkQueue commonSubmitterQueue() {
+        ForkJoinPool p = common;
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; int n;
+        return (p != null && (ws = p.workQueues) != null &&
+                (n = ws.length) > 0) ?
+            ws[(n - 1) & r & SQMASK] : null;
+    }
+
+    /**
+     * Performs tryUnpush for an external submitter.
+     */
+    final boolean tryExternalUnpush(ForkJoinTask<?> task) {
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; WorkQueue w; int n;
+        return ((ws = workQueues) != null &&
+                (n = ws.length) > 0 &&
+                (w = ws[(n - 1) & r & SQMASK]) != null &&
+                w.trySharedUnpush(task));
+    }
+
+    /**
+     * Performs helpComplete for an external submitter.
+     */
+    final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; WorkQueue w; int n;
+        return ((ws = workQueues) != null && (n = ws.length) > 0 &&
+                (w = ws[(n - 1) & r & SQMASK]) != null) ?
+            w.sharedHelpCC(task, maxTasks) : 0;
+    }
+
+    /**
+     * Tries to steal and run tasks within the target's computation.
+     * The maxTasks argument supports external usages; internal calls
+     * use zero, allowing unbounded steps (external calls trap
+     * non-positive values).
+     *
+     * @param w caller
+     * @param maxTasks if non-zero, the maximum number of other tasks to run
+     * @return task status on exit
+     */
+    final int helpComplete(WorkQueue w, CountedCompleter<?> task,
+                           int maxTasks) {
+        return (w == null) ? 0 : w.localHelpCC(task, maxTasks);
     }
 
     /**
@@ -2383,10 +2030,12 @@
      */
     static int getSurplusQueuedTaskCount() {
         Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
-        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
-            int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK;
-            int n = (q = wt.workQueue).top - q.base;
-            int a = (int)(pool.ctl >> AC_SHIFT) + p;
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (pool = (wt = (ForkJoinWorkerThread)t).pool) != null &&
+            (q = wt.workQueue) != null) {
+            int p = pool.mode & SMASK;
+            int a = p + (int)(pool.ctl >> RC_SHIFT);
+            int n = q.top - q.base;
             return n - (a > (p >>>= 1) ? 0 :
                         a > (p >>>= 1) ? 1 :
                         a > (p >>>= 1) ? 2 :
@@ -2396,7 +2045,7 @@
         return 0;
     }
 
-    //  Termination
+    // Termination
 
     /**
      * Possibly initiates and/or completes termination.
@@ -2404,198 +2053,86 @@
      * @param now if true, unconditionally terminate, else only
      * if no work and no active workers
      * @param enable if true, terminate when next possible
-     * @return -1: terminating/terminated, 0: retry if internal caller, else 1
+     * @return true if terminating or terminated
      */
-    private int tryTerminate(boolean now, boolean enable) {
-        int rs; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
+    private boolean tryTerminate(boolean now, boolean enable) {
+        int md; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
 
-        while ((rs = runState) >= 0) {
+        while (((md = mode) & SHUTDOWN) == 0) {
             if (!enable || this == common)        // cannot shutdown
-                return 1;
-            else if (rs == 0)
-                tryInitialize(false);             // ensure initialized
+                return false;
             else
-                U.compareAndSwapInt(this, RUNSTATE, rs, rs | SHUTDOWN);
+                MODE.compareAndSet(this, md, md | SHUTDOWN);
         }
 
-        if ((rs & STOP) == 0) {                   // try to initiate termination
-            if (!now) {                           // check quiescence
+        while (((md = mode) & STOP) == 0) {       // try to initiate termination
+            if (!now) {                           // check if quiescent & empty
                 for (long oldSum = 0L;;) {        // repeat until stable
-                    WorkQueue[] ws; WorkQueue w; int b;
+                    boolean running = false;
                     long checkSum = ctl;
-                    if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
-                        return 0;                 // still active workers
-                    if ((ws = workQueues) != null) {
+                    WorkQueue[] ws = workQueues;
+                    if ((md & SMASK) + (int)(checkSum >> RC_SHIFT) > 0)
+                        running = true;
+                    else if (ws != null) {
+                        WorkQueue w; int b;
                         for (int i = 0; i < ws.length; ++i) {
                             if ((w = ws[i]) != null) {
-                                checkSum += (b = w.base);
-                                if (w.currentSteal != null || b != w.top)
-                                    return 0;     // retry if internal caller
+                                checkSum += (b = w.base) + w.id;
+                                if (b != w.top ||
+                                    ((i & 1) == 1 && w.source >= 0)) {
+                                    running = true;
+                                    break;
+                                }
                             }
                         }
                     }
-                    if (oldSum == (oldSum = checkSum))
+                    if (((md = mode) & STOP) != 0)
+                        break;                 // already triggered
+                    else if (running)
+                        return false;
+                    else if (workQueues == ws && oldSum == (oldSum = checkSum))
                         break;
                 }
             }
-            do {} while (!U.compareAndSwapInt(this, RUNSTATE,
-                                              rs = runState, rs | STOP));
+            if ((md & STOP) == 0)
+                MODE.compareAndSet(this, md, md | STOP);
         }
 
-        for (long oldSum = 0L;;) {                // repeat until stable
-            WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt;
-            long checkSum = ctl;
-            if ((ws = workQueues) != null) {      // help terminate others
-                for (int i = 0; i < ws.length; ++i) {
-                    if ((w = ws[i]) != null) {
-                        w.cancelAll();            // clear queues
-                        checkSum += w.base;
-                        if (w.qlock >= 0) {
-                            w.qlock = -1;         // racy set OK
-                            if ((wt = w.owner) != null) {
+        while (((md = mode) & TERMINATED) == 0) { // help terminate others
+            for (long oldSum = 0L;;) {            // repeat until stable
+                WorkQueue[] ws; WorkQueue w;
+                long checkSum = ctl;
+                if ((ws = workQueues) != null) {
+                    for (int i = 0; i < ws.length; ++i) {
+                        if ((w = ws[i]) != null) {
+                            ForkJoinWorkerThread wt = w.owner;
+                            w.cancelAll();        // clear queues
+                            if (wt != null) {
                                 try {             // unblock join or park
                                     wt.interrupt();
                                 } catch (Throwable ignore) {
                                 }
                             }
+                            checkSum += w.base + w.id;
                         }
                     }
                 }
-            }
-            if (oldSum == (oldSum = checkSum))
-                break;
-        }
-
-        if ((short)(ctl >>> TC_SHIFT) + (config & SMASK) <= 0) {
-            runState = (STARTED | SHUTDOWN | STOP | TERMINATED); // final write
-            synchronized (this) {
-                notifyAll();                      // for awaitTermination
+                if (((md = mode) & TERMINATED) != 0 ||
+                    (workQueues == ws && oldSum == (oldSum = checkSum)))
+                    break;
             }
-        }
-
-        return -1;
-    }
-
-    // External operations
-
-    /**
-     * Constructs and tries to install a new external queue,
-     * failing if the workQueues array already has a queue at
-     * the given index.
-     *
-     * @param index the index of the new queue
-     */
-    private void tryCreateExternalQueue(int index) {
-        AuxState aux;
-        if ((aux = auxState) != null && index >= 0) {
-            WorkQueue q = new WorkQueue(this, null);
-            q.config = index;
-            q.scanState = ~UNSIGNALLED;
-            q.qlock = 1;                   // lock queue
-            boolean installed = false;
-            aux.lock();
-            try {                          // lock pool to install
-                WorkQueue[] ws;
-                if ((ws = workQueues) != null && index < ws.length &&
-                    ws[index] == null) {
-                    ws[index] = q;         // else throw away
-                    installed = true;
+            if ((md & TERMINATED) != 0)
+                break;
+            else if ((md & SMASK) + (short)(ctl >>> TC_SHIFT) > 0)
+                break;
+            else if (MODE.compareAndSet(this, md, md | TERMINATED)) {
+                synchronized (this) {
+                    notifyAll();                  // for awaitTermination
                 }
-            } finally {
-                aux.unlock();
-            }
-            if (installed) {
-                try {
-                    q.growArray();
-                } finally {
-                    q.qlock = 0;
-                }
+                break;
             }
         }
-    }
-
-    /**
-     * Adds the given task to a submission queue at submitter's
-     * current queue. Also performs secondary initialization upon the
-     * first submission of the first task to the pool, and detects
-     * first submission by an external thread and creates a new shared
-     * queue if the one at index if empty or contended.
-     *
-     * @param task the task. Caller must ensure non-null.
-     */
-    final void externalPush(ForkJoinTask<?> task) {
-        int r;                            // initialize caller's probe
-        if ((r = ThreadLocalRandom.getProbe()) == 0) {
-            ThreadLocalRandom.localInit();
-            r = ThreadLocalRandom.getProbe();
-        }
-        for (;;) {
-            WorkQueue q; int wl, k, stat;
-            int rs = runState;
-            WorkQueue[] ws = workQueues;
-            if (rs <= 0 || ws == null || (wl = ws.length) <= 0)
-                tryInitialize(true);
-            else if ((q = ws[k = (wl - 1) & r & SQMASK]) == null)
-                tryCreateExternalQueue(k);
-            else if ((stat = q.sharedPush(task)) < 0)
-                break;
-            else if (stat == 0) {
-                signalWork();
-                break;
-            }
-            else                          // move if busy
-                r = ThreadLocalRandom.advanceProbe(r);
-        }
-    }
-
-    /**
-     * Pushes a possibly-external submission.
-     */
-    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
-        Thread t; ForkJoinWorkerThread w; WorkQueue q;
-        if (task == null)
-            throw new NullPointerException();
-        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
-            (w = (ForkJoinWorkerThread)t).pool == this &&
-            (q = w.workQueue) != null)
-            q.push(task);
-        else
-            externalPush(task);
-        return task;
-    }
-
-    /**
-     * Returns common pool queue for an external thread.
-     */
-    static WorkQueue commonSubmitterQueue() {
-        ForkJoinPool p = common;
-        int r = ThreadLocalRandom.getProbe();
-        WorkQueue[] ws; int wl;
-        return (p != null && (ws = p.workQueues) != null &&
-                (wl = ws.length) > 0) ?
-            ws[(wl - 1) & r & SQMASK] : null;
-    }
-
-    /**
-     * Performs tryUnpush for an external submitter.
-     */
-    final boolean tryExternalUnpush(ForkJoinTask<?> task) {
-        int r = ThreadLocalRandom.getProbe();
-        WorkQueue[] ws; WorkQueue w; int wl;
-        return ((ws = workQueues) != null &&
-                (wl = ws.length) > 0 &&
-                (w = ws[(wl - 1) & r & SQMASK]) != null &&
-                w.trySharedUnpush(task));
-    }
-
-    /**
-     * Performs helpComplete for an external submitter.
-     */
-    final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
-        WorkQueue[] ws; int wl;
-        int r = ThreadLocalRandom.getProbe();
-        return ((ws = workQueues) != null && (wl = ws.length) > 0) ?
-            helpComplete(ws[(wl - 1) & r & SQMASK], task, maxTasks) : 0;
+        return true;
     }
 
     // Exported methods
@@ -2604,9 +2141,10 @@
 
     /**
      * Creates a {@code ForkJoinPool} with parallelism equal to {@link
-     * java.lang.Runtime#availableProcessors}, using the {@linkplain
-     * #defaultForkJoinWorkerThreadFactory default thread factory},
-     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     * java.lang.Runtime#availableProcessors}, using defaults for all
+     * other parameters (see {@link #ForkJoinPool(int,
+     * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
+     * int, int, int, Predicate, long, TimeUnit)}).
      *
      * @throws SecurityException if a security manager exists and
      *         the caller is not permitted to modify threads
@@ -2615,14 +2153,16 @@
      */
     public ForkJoinPool() {
         this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
-             defaultForkJoinWorkerThreadFactory, null, false);
+             defaultForkJoinWorkerThreadFactory, null, false,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
     }
 
     /**
      * Creates a {@code ForkJoinPool} with the indicated parallelism
-     * level, the {@linkplain
-     * #defaultForkJoinWorkerThreadFactory default thread factory},
-     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     * level, using defaults for all other parameters (see {@link
+     * #ForkJoinPool(int, ForkJoinWorkerThreadFactory,
+     * UncaughtExceptionHandler, boolean, int, int, int, Predicate,
+     * long, TimeUnit)}).
      *
      * @param parallelism the parallelism level
      * @throws IllegalArgumentException if parallelism less than or
@@ -2633,11 +2173,15 @@
      *         java.lang.RuntimePermission}{@code ("modifyThread")}
      */
     public ForkJoinPool(int parallelism) {
-        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
+        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
     }
 
     /**
-     * Creates a {@code ForkJoinPool} with the given parameters.
+     * Creates a {@code ForkJoinPool} with the given parameters (using
+     * defaults for others -- see {@link #ForkJoinPool(int,
+     * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
+     * int, int, int, Predicate, long, TimeUnit)}).
      *
      * @param parallelism the parallelism level. For default value,
      * use {@link java.lang.Runtime#availableProcessors}.
@@ -2664,43 +2208,185 @@
                         ForkJoinWorkerThreadFactory factory,
                         UncaughtExceptionHandler handler,
                         boolean asyncMode) {
-        this(checkParallelism(parallelism),
-             checkFactory(factory),
-             handler,
-             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
-             "ForkJoinPool-" + nextPoolId() + "-worker-");
+        this(parallelism, factory, handler, asyncMode,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the given parameters.
+     *
+     * @param parallelism the parallelism level. For default value,
+     * use {@link java.lang.Runtime#availableProcessors}.
+     *
+     * @param factory the factory for creating new threads. For
+     * default value, use {@link #defaultForkJoinWorkerThreadFactory}.
+     *
+     * @param handler the handler for internal worker threads that
+     * terminate due to unrecoverable errors encountered while
+     * executing tasks. For default value, use {@code null}.
+     *
+     * @param asyncMode if true, establishes local first-in-first-out
+     * scheduling mode for forked tasks that are never joined. This
+     * mode may be more appropriate than default locally stack-based
+     * mode in applications in which worker threads only process
+     * event-style asynchronous tasks.  For default value, use {@code
+     * false}.
+     *
+     * @param corePoolSize the number of threads to keep in the pool
+     * (unless timed out after an elapsed keep-alive). Normally (and
+     * by default) this is the same value as the parallelism level,
+     * but may be set to a larger value to reduce dynamic overhead if
+     * tasks regularly block. Using a smaller value (for example
+     * {@code 0}) has the same effect as the default.
+     *
+     * @param maximumPoolSize the maximum number of threads allowed.
+     * When the maximum is reached, attempts to replace blocked
+     * threads fail.  (However, because creation and termination of
+     * different threads may overlap, and may be managed by the given
+     * thread factory, this value may be transiently exceeded.)  To
+     * arrange the same value as is used by default for the common
+     * pool, use {@code 256} plus the {@code parallelism} level. (By
+     * default, the common pool allows a maximum of 256 spare
+     * threads.)  Using a value (for example {@code
+     * Integer.MAX_VALUE}) larger than the implementation's total
+     * thread limit has the same effect as using this limit (which is
+     * the default).
+     *
+     * @param minimumRunnable the minimum allowed number of core
+     * threads not blocked by a join or {@link ManagedBlocker}.  To
+     * ensure progress, when too few unblocked threads exist and
+     * unexecuted tasks may exist, new threads are constructed, up to
+     * the given maximumPoolSize.  For the default value, use {@code
+     * 1}, that ensures liveness.  A larger value might improve
+     * throughput in the presence of blocked activities, but might
+     * not, due to increased overhead.  A value of zero may be
+     * acceptable when submitted tasks cannot have dependencies
+     * requiring additional threads.
+     *
+     * @param saturate if non-null, a predicate invoked upon attempts
+     * to create more than the maximum total allowed threads.  By
+     * default, when a thread is about to block on a join or {@link
+     * ManagedBlocker}, but cannot be replaced because the
+     * maximumPoolSize would be exceeded, a {@link
+     * RejectedExecutionException} is thrown.  But if this predicate
+     * returns {@code true}, then no exception is thrown, so the pool
+     * continues to operate with fewer than the target number of
+     * runnable threads, which might not ensure progress.
+     *
+     * @param keepAliveTime the elapsed time since last use before
+     * a thread is terminated (and then later replaced if needed).
+     * For the default value, use {@code 60, TimeUnit.SECONDS}.
+     *
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     *
+     * @throws IllegalArgumentException if parallelism is less than or
+     *         equal to zero, or is greater than implementation limit,
+     *         or if maximumPoolSize is less than parallelism,
+     *         of if the keepAliveTime is less than or equal to zero.
+     * @throws NullPointerException if the factory is null
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     * @since 9
+     */
+    public ForkJoinPool(int parallelism,
+                        ForkJoinWorkerThreadFactory factory,
+                        UncaughtExceptionHandler handler,
+                        boolean asyncMode,
+                        int corePoolSize,
+                        int maximumPoolSize,
+                        int minimumRunnable,
+                        Predicate<? super ForkJoinPool> saturate,
+                        long keepAliveTime,
+                        TimeUnit unit) {
+        // check, encode, pack parameters
+        if (parallelism <= 0 || parallelism > MAX_CAP ||
+            maximumPoolSize < parallelism || keepAliveTime <= 0L)
+            throw new IllegalArgumentException();
+        if (factory == null)
+            throw new NullPointerException();
+        long ms = Math.max(unit.toMillis(keepAliveTime), TIMEOUT_SLOP);
+
+        String prefix = "ForkJoinPool-" + nextPoolId() + "-worker-";
+        int corep = Math.min(Math.max(corePoolSize, parallelism), MAX_CAP);
+        long c = ((((long)(-corep)       << TC_SHIFT) & TC_MASK) |
+                  (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
+        int m = parallelism | (asyncMode ? FIFO : 0);
+        int maxSpares = Math.min(maximumPoolSize, MAX_CAP) - parallelism;
+        int minAvail = Math.min(Math.max(minimumRunnable, 0), MAX_CAP);
+        int b = ((minAvail - parallelism) & SMASK) | (maxSpares << SWIDTH);
+        int n = (parallelism > 1) ? parallelism - 1 : 1; // at least 2 slots
+        n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
+        n = (n + 1) << 1; // power of two, including space for submission queues
+
+        this.workQueues = new WorkQueue[n];
+        this.workerNamePrefix = prefix;
+        this.factory = factory;
+        this.ueh = handler;
+        this.saturate = saturate;
+        this.keepAlive = ms;
+        this.bounds = b;
+        this.mode = m;
+        this.ctl = c;
         checkPermission();
     }
 
-    private static int checkParallelism(int parallelism) {
-        if (parallelism <= 0 || parallelism > MAX_CAP)
-            throw new IllegalArgumentException();
-        return parallelism;
-    }
-
-    private static ForkJoinWorkerThreadFactory checkFactory
-        (ForkJoinWorkerThreadFactory factory) {
-        if (factory == null)
-            throw new NullPointerException();
-        return factory;
-    }
+    /**
+     * Constructor for common pool using parameters possibly
+     * overridden by system properties
+     */
+    @SuppressWarnings("deprecation") // Class.newInstance
+    private ForkJoinPool(byte forCommonPoolOnly) {
+        int parallelism = -1;
+        ForkJoinWorkerThreadFactory fac = null;
+        UncaughtExceptionHandler handler = null;
+        try {  // ignore exceptions in accessing/parsing properties
+            String pp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.parallelism");
+            String fp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.threadFactory");
+            String hp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
+            if (pp != null)
+                parallelism = Integer.parseInt(pp);
+            if (fp != null)
+                fac = ((ForkJoinWorkerThreadFactory)ClassLoader.
+                           getSystemClassLoader().loadClass(fp).newInstance());
+            if (hp != null)
+                handler = ((UncaughtExceptionHandler)ClassLoader.
+                           getSystemClassLoader().loadClass(hp).newInstance());
+        } catch (Exception ignore) {
+        }
 
-    /**
-     * Creates a {@code ForkJoinPool} with the given parameters, without
-     * any security checks or parameter validation.  Invoked directly by
-     * makeCommonPool.
-     */
-    private ForkJoinPool(int parallelism,
-                         ForkJoinWorkerThreadFactory factory,
-                         UncaughtExceptionHandler handler,
-                         int mode,
-                         String workerNamePrefix) {
-        this.workerNamePrefix = workerNamePrefix;
-        this.factory = factory;
+        if (fac == null) {
+            if (System.getSecurityManager() == null)
+                fac = defaultForkJoinWorkerThreadFactory;
+            else // use security-managed default
+                fac = new InnocuousForkJoinWorkerThreadFactory();
+        }
+        if (parallelism < 0 && // default 1 less than #cores
+            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
+            parallelism = 1;
+        if (parallelism > MAX_CAP)
+            parallelism = MAX_CAP;
+
+        long c = ((((long)(-parallelism) << TC_SHIFT) & TC_MASK) |
+                  (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
+        int b = ((1 - parallelism) & SMASK) | (COMMON_MAX_SPARES << SWIDTH);
+        int n = (parallelism > 1) ? parallelism - 1 : 1;
+        n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
+        n = (n + 1) << 1;
+
+        this.workQueues = new WorkQueue[n];
+        this.workerNamePrefix = "ForkJoinPool.commonPool-worker-";
+        this.factory = fac;
         this.ueh = handler;
-        this.config = (parallelism & SMASK) | mode;
-        long np = (long)(-parallelism); // offset ctl counts
-        this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
+        this.saturate = null;
+        this.keepAlive = DEFAULT_KEEPALIVE;
+        this.bounds = b;
+        this.mode = parallelism;
+        this.ctl = c;
     }
 
     /**
@@ -2876,8 +2562,8 @@
      * @return the targeted parallelism level of this pool
      */
     public int getParallelism() {
-        int par;
-        return ((par = config & SMASK) > 0) ? par : 1;
+        int par = mode & SMASK;
+        return (par > 0) ? par : 1;
     }
 
     /**
@@ -2899,7 +2585,7 @@
      * @return the number of worker threads
      */
     public int getPoolSize() {
-        return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
+        return ((mode & SMASK) + (short)(ctl >>> TC_SHIFT));
     }
 
     /**
@@ -2909,7 +2595,7 @@
      * @return {@code true} if this pool uses async mode
      */
     public boolean getAsyncMode() {
-        return (config & FIFO_QUEUE) != 0;
+        return (mode & FIFO) != 0;
     }
 
     /**
@@ -2940,7 +2626,7 @@
      * @return the number of active threads
      */
     public int getActiveThreadCount() {
-        int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
+        int r = (mode & SMASK) + (int)(ctl >> RC_SHIFT);
         return (r <= 0) ? 0 : r; // suppress momentarily negative values
     }
 
@@ -2956,7 +2642,30 @@
      * @return {@code true} if all threads are currently idle
      */
     public boolean isQuiescent() {
-        return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0;
+        for (;;) {
+            long c = ctl;
+            int md = mode, pc = md & SMASK;
+            int tc = pc + (short)(c >>> TC_SHIFT);
+            int rc = pc + (int)(c >> RC_SHIFT);
+            if ((md & (STOP | TERMINATED)) != 0)
+                return true;
+            else if (rc > 0)
+                return false;
+            else {
+                WorkQueue[] ws; WorkQueue v;
+                if ((ws = workQueues) != null) {
+                    for (int i = 1; i < ws.length; i += 2) {
+                        if ((v = ws[i]) != null) {
+                            if ((v.source & QUIET) == 0)
+                                return false;
+                            --tc;
+                        }
+                    }
+                }
+                if (tc == 0 && ctl == c)
+                    return true;
+            }
+        }
     }
 
     /**
@@ -2971,13 +2680,12 @@
      * @return the number of steals
      */
     public long getStealCount() {
-        AuxState sc = auxState;
-        long count = (sc == null) ? 0L : sc.stealCount;
+        long count = stealCount;
         WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
-                    count += w.nsteals;
+                    count += (long)w.nsteals & 0xffffffffL;
             }
         }
         return count;
@@ -3049,15 +2757,7 @@
      * @return the next submission, or {@code null} if none
      */
     protected ForkJoinTask<?> pollSubmission() {
-        WorkQueue[] ws; int wl; WorkQueue w; ForkJoinTask<?> t;
-        int r = ThreadLocalRandom.nextSecondarySeed();
-        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
-            for (int m = wl - 1, i = 0; i < wl; ++i) {
-                if ((w = ws[(i << 1) & m]) != null && (t = w.poll()) != null)
-                    return t;
-            }
-        }
-        return null;
+        return pollScan(true);
     }
 
     /**
@@ -3103,9 +2803,7 @@
     public String toString() {
         // Use a single pass through workQueues to collect counts
         long qt = 0L, qs = 0L; int rc = 0;
-        AuxState sc = auxState;
-        long st = (sc == null) ? 0L : sc.stealCount;
-        long c = ctl;
+        long st = stealCount;
         WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; ++i) {
@@ -3115,22 +2813,24 @@
                         qs += size;
                     else {
                         qt += size;
-                        st += w.nsteals;
+                        st += (long)w.nsteals & 0xffffffffL;
                         if (w.isApparentlyUnblocked())
                             ++rc;
                     }
                 }
             }
         }
-        int pc = (config & SMASK);
+
+        int md = mode;
+        int pc = (md & SMASK);
+        long c = ctl;
         int tc = pc + (short)(c >>> TC_SHIFT);
-        int ac = pc + (int)(c >> AC_SHIFT);
+        int ac = pc + (int)(c >> RC_SHIFT);
         if (ac < 0) // ignore transient negative
             ac = 0;
-        int rs = runState;
-        String level = ((rs & TERMINATED) != 0 ? "Terminated" :
-                        (rs & STOP)       != 0 ? "Terminating" :
-                        (rs & SHUTDOWN)   != 0 ? "Shutting down" :
+        String level = ((md & TERMINATED) != 0 ? "Terminated" :
+                        (md & STOP)       != 0 ? "Terminating" :
+                        (md & SHUTDOWN)   != 0 ? "Shutting down" :
                         "Running");
         return super.toString() +
             "[" + level +
@@ -3193,7 +2893,7 @@
      * @return {@code true} if all tasks have completed following shut down
      */
     public boolean isTerminated() {
-        return (runState & TERMINATED) != 0;
+        return (mode & TERMINATED) != 0;
     }
 
     /**
@@ -3210,8 +2910,8 @@
      * @return {@code true} if terminating but not yet terminated
      */
     public boolean isTerminating() {
-        int rs = runState;
-        return (rs & STOP) != 0 && (rs & TERMINATED) == 0;
+        int md = mode;
+        return (md & STOP) != 0 && (md & TERMINATED) == 0;
     }
 
     /**
@@ -3220,7 +2920,7 @@
      * @return {@code true} if this pool has been shut down
      */
     public boolean isShutdown() {
-        return (runState & SHUTDOWN) != 0;
+        return (mode & SHUTDOWN) != 0;
     }
 
     /**
@@ -3284,30 +2984,19 @@
             helpQuiescePool(wt.workQueue);
             return true;
         }
-        long startTime = System.nanoTime();
-        WorkQueue[] ws;
-        int r = 0, wl;
-        boolean found = true;
-        while (!isQuiescent() && (ws = workQueues) != null &&
-               (wl = ws.length) > 0) {
-            if (!found) {
-                if ((System.nanoTime() - startTime) > nanos)
+        else {
+            for (long startTime = System.nanoTime();;) {
+                ForkJoinTask<?> t;
+                if ((t = pollScan(false)) != null)
+                    t.doExec();
+                else if (isQuiescent())
+                    return true;
+                else if ((System.nanoTime() - startTime) > nanos)
                     return false;
-                Thread.yield(); // cannot block
-            }
-            found = false;
-            for (int m = wl - 1, j = (m + 1) << 2; j >= 0; --j) {
-                ForkJoinTask<?> t; WorkQueue q; int b, k;
-                if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null &&
-                    (b = q.base) - q.top < 0) {
-                    found = true;
-                    if ((t = q.pollAt(b)) != null)
-                        t.doExec();
-                    break;
-                }
+                else
+                    Thread.yield(); // cannot block
             }
         }
-        return true;
     }
 
     /**
@@ -3422,17 +3111,19 @@
         throws InterruptedException {
         ForkJoinPool p;
         ForkJoinWorkerThread wt;
+        WorkQueue w;
         Thread t = Thread.currentThread();
         if ((t instanceof ForkJoinWorkerThread) &&
-            (p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
-            WorkQueue w = wt.workQueue;
+            (p = (wt = (ForkJoinWorkerThread)t).pool) != null &&
+            (w = wt.workQueue) != null) {
+            int block;
             while (!blocker.isReleasable()) {
-                if (p.tryCompensate(w)) {
+                if ((block = p.tryCompensate(w)) != 0) {
                     try {
                         do {} while (!blocker.isReleasable() &&
                                      !blocker.block());
                     } finally {
-                        U.getAndAddLong(p, CTL, AC_UNIT);
+                        CTL.getAndAdd(p, (block > 0) ? RC_UNIT : 0L);
                     }
                     break;
                 }
@@ -3444,6 +3135,55 @@
         }
     }
 
+    /**
+     * If the given executor is a ForkJoinPool, poll and execute
+     * AsynchronousCompletionTasks from worker's queue until none are
+     * available or blocker is released.
+     */
+    static void helpAsyncBlocker(Executor e, ManagedBlocker blocker) {
+        if (blocker != null && (e instanceof ForkJoinPool)) {
+            WorkQueue w; ForkJoinWorkerThread wt; WorkQueue[] ws; int r, n;
+            ForkJoinPool p = (ForkJoinPool)e;
+            Thread thread = Thread.currentThread();
+            if (thread instanceof ForkJoinWorkerThread &&
+                (wt = (ForkJoinWorkerThread)thread).pool == p)
+                w = wt.workQueue;
+            else if ((r = ThreadLocalRandom.getProbe()) != 0 &&
+                     (ws = p.workQueues) != null && (n = ws.length) > 0)
+                w = ws[(n - 1) & r & SQMASK];
+            else
+                w = null;
+            if (w != null) {
+                for (;;) {
+                    int b = w.base, s = w.top, d, al; ForkJoinTask<?>[] a;
+                    if ((a = w.array) != null && (d = b - s) < 0 &&
+                        (al = a.length) > 0) {
+                        int index = (al - 1) & b;
+                        ForkJoinTask<?> t = (ForkJoinTask<?>)
+                            QA.getAcquire(a, index);
+                        if (blocker.isReleasable())
+                            break;
+                        else if (b++ == w.base) {
+                            if (t == null) {
+                                if (d == -1)
+                                    break;
+                            }
+                            else if (!(t instanceof CompletableFuture.
+                                  AsynchronousCompletionTask))
+                                break;
+                            else if (QA.compareAndSet(a, index, t, null)) {
+                                w.base = b;
+                                t.doExec();
+                            }
+                        }
+                    }
+                    else
+                        break;
+                }
+            }
+        }
+    }
+
     // AbstractExecutorService overrides.  These rely on undocumented
     // fact that ForkJoinTask.adapt returns ForkJoinTasks that also
     // implement RunnableFuture.
@@ -3456,24 +3196,17 @@
         return new ForkJoinTask.AdaptedCallable<T>(callable);
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long CTL;
-    private static final long RUNSTATE;
-    private static final int ABASE;
-    private static final int ASHIFT;
+    // VarHandle mechanics
+    private static final VarHandle CTL;
+    private static final VarHandle MODE;
+    private static final VarHandle QA;
 
     static {
         try {
-            CTL = U.objectFieldOffset
-                (ForkJoinPool.class.getDeclaredField("ctl"));
-            RUNSTATE = U.objectFieldOffset
-                (ForkJoinPool.class.getDeclaredField("runState"));
-            ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
-            int scale = U.arrayIndexScale(ForkJoinTask[].class);
-            if ((scale & (scale - 1)) != 0)
-                throw new Error("array index scale not a power of two");
-            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            CTL = l.findVarHandle(ForkJoinPool.class, "ctl", long.class);
+            MODE = l.findVarHandle(ForkJoinPool.class, "mode", int.class);
+            QA = MethodHandles.arrayElementVarHandle(ForkJoinTask[].class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
@@ -3497,51 +3230,10 @@
 
         common = java.security.AccessController.doPrivileged
             (new java.security.PrivilegedAction<ForkJoinPool>() {
-                public ForkJoinPool run() { return makeCommonPool(); }});
-
-        // report 1 even if threads disabled
-        COMMON_PARALLELISM = Math.max(common.config & SMASK, 1);
-    }
+                    public ForkJoinPool run() {
+                        return new ForkJoinPool((byte)0); }});
 
-    /**
-     * Creates and returns the common pool, respecting user settings
-     * specified via system properties.
-     */
-    @SuppressWarnings("deprecation") // Class.newInstance
-    static ForkJoinPool makeCommonPool() {
-        int parallelism = -1;
-        ForkJoinWorkerThreadFactory factory = null;
-        UncaughtExceptionHandler handler = null;
-        try {  // ignore exceptions in accessing/parsing properties
-            String pp = System.getProperty
-                ("java.util.concurrent.ForkJoinPool.common.parallelism");
-            String fp = System.getProperty
-                ("java.util.concurrent.ForkJoinPool.common.threadFactory");
-            String hp = System.getProperty
-                ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
-            if (pp != null)
-                parallelism = Integer.parseInt(pp);
-            if (fp != null)
-                factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
-                           getSystemClassLoader().loadClass(fp).newInstance());
-            if (hp != null)
-                handler = ((UncaughtExceptionHandler)ClassLoader.
-                           getSystemClassLoader().loadClass(hp).newInstance());
-        } catch (Exception ignore) {
-        }
-        if (factory == null) {
-            if (System.getSecurityManager() == null)
-                factory = defaultForkJoinWorkerThreadFactory;
-            else // use security-managed default
-                factory = new InnocuousForkJoinWorkerThreadFactory();
-        }
-        if (parallelism < 0 && // default 1 less than #cores
-            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
-            parallelism = 1;
-        if (parallelism > MAX_CAP)
-            parallelism = MAX_CAP;
-        return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
-                                "ForkJoinPool.commonPool-worker-");
+        COMMON_PARALLELISM = Math.max(common.mode & SMASK, 1);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Wed Jul 05 22:00:06 2017 +0200
@@ -36,6 +36,8 @@
 package java.util.concurrent;
 
 import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
@@ -92,7 +94,7 @@
  * encountering the exception; minimally only the latter.
  *
  * <p>It is possible to define and use ForkJoinTasks that may block,
- * but doing do requires three further considerations: (1) Completion
+ * but doing so requires three further considerations: (1) Completion
  * of few if any <em>other</em> tasks should be dependent on a task
  * that blocks on external synchronization or I/O. Event-style async
  * tasks that are never joined (for example, those subclassing {@link
@@ -259,7 +261,7 @@
         for (int s;;) {
             if ((s = status) < 0)
                 return s;
-            if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
+            if (STATUS.compareAndSet(this, s, s | completion)) {
                 if ((s >>> 16) != 0)
                     synchronized (this) { notifyAll(); }
                 return completion;
@@ -297,7 +299,7 @@
     final void internalWait(long timeout) {
         int s;
         if ((s = status) >= 0 && // force completer to issue notify
-            U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+            STATUS.compareAndSet(this, s, s | SIGNAL)) {
             synchronized (this) {
                 if (status >= 0)
                     try { wait(timeout); } catch (InterruptedException ie) { }
@@ -319,7 +321,7 @@
         if (s >= 0 && (s = status) >= 0) {
             boolean interrupted = false;
             do {
-                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                if (STATUS.compareAndSet(this, s, s | SIGNAL)) {
                     synchronized (this) {
                         if (status >= 0) {
                             try {
@@ -353,7 +355,7 @@
                   ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
                   0)) >= 0) {
             while ((s = status) >= 0) {
-                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                if (STATUS.compareAndSet(this, s, s | SIGNAL)) {
                     synchronized (this) {
                         if (status >= 0)
                             wait(0L);
@@ -400,22 +402,24 @@
     // Exception table support
 
     /**
-     * Table of exceptions thrown by tasks, to enable reporting by
-     * callers. Because exceptions are rare, we don't directly keep
+     * Hash table of exceptions thrown by tasks, to enable reporting
+     * by callers. Because exceptions are rare, we don't directly keep
      * them with task objects, but instead use a weak ref table.  Note
      * that cancellation exceptions don't appear in the table, but are
      * instead recorded as status values.
      *
-     * Note: These statics are initialized below in static block.
+     * The exception table has a fixed capacity.
      */
-    private static final ExceptionNode[] exceptionTable;
-    private static final ReentrantLock exceptionTableLock;
-    private static final ReferenceQueue<Object> exceptionTableRefQueue;
+    private static final ExceptionNode[] exceptionTable
+        = new ExceptionNode[32];
 
-    /**
-     * Fixed capacity for exceptionTable.
-     */
-    private static final int EXCEPTION_MAP_CAPACITY = 32;
+    /** Lock protecting access to exceptionTable. */
+    private static final ReentrantLock exceptionTableLock
+        = new ReentrantLock();
+
+    /** Reference queue of stale exceptionally completed tasks. */
+    private static final ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue
+        = new ReferenceQueue<ForkJoinTask<?>>();
 
     /**
      * Key-value nodes for exception table.  The chained hash table
@@ -435,7 +439,7 @@
         final long thrower;  // use id not ref to avoid weak cycles
         final int hashCode;  // store task hashCode before weak ref disappears
         ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next,
-                      ReferenceQueue<Object> exceptionTableRefQueue) {
+                      ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue) {
             super(task, exceptionTableRefQueue);
             this.ex = ex;
             this.next = next;
@@ -599,9 +603,8 @@
     private static void expungeStaleExceptions() {
         for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
             if (x instanceof ExceptionNode) {
-                int hashCode = ((ExceptionNode)x).hashCode;
                 ExceptionNode[] t = exceptionTable;
-                int i = hashCode & (t.length - 1);
+                int i = ((ExceptionNode)x).hashCode & (t.length - 1);
                 ExceptionNode e = t[i];
                 ExceptionNode pred = null;
                 while (e != null) {
@@ -1031,7 +1034,7 @@
                 while ((s = status) >= 0 &&
                        (ns = deadline - System.nanoTime()) > 0L) {
                     if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
-                        U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                        STATUS.compareAndSet(this, s, s | SIGNAL)) {
                         synchronized (this) {
                             if (status >= 0)
                                 wait(ms); // OK to throw InterruptedException
@@ -1324,8 +1327,8 @@
      */
     public final short setForkJoinTaskTag(short newValue) {
         for (int s;;) {
-            if (U.compareAndSwapInt(this, STATUS, s = status,
-                                    (s & ~SMASK) | (newValue & SMASK)))
+            if (STATUS.compareAndSet(this, s = status,
+                                     (s & ~SMASK) | (newValue & SMASK)))
                 return (short)s;
         }
     }
@@ -1348,8 +1351,8 @@
         for (int s;;) {
             if ((short)(s = status) != expect)
                 return false;
-            if (U.compareAndSwapInt(this, STATUS, s,
-                                    (s & ~SMASK) | (update & SMASK)))
+            if (STATUS.compareAndSet(this, s,
+                                     (s & ~SMASK) | (update & SMASK)))
                 return true;
         }
     }
@@ -1510,17 +1513,12 @@
             setExceptionalCompletion((Throwable)ex);
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long STATUS;
-
+    // VarHandle mechanics
+    private static final VarHandle STATUS;
     static {
-        exceptionTableLock = new ReentrantLock();
-        exceptionTableRefQueue = new ReferenceQueue<Object>();
-        exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
         try {
-            STATUS = U.objectFieldOffset
-                (ForkJoinTask.class.getDeclaredField("status"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATUS = l.findVarHandle(ForkJoinTask.class, "status", int.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java	Wed Jul 05 22:00:06 2017 +0200
@@ -66,8 +66,9 @@
      * owning thread.
      *
      * Support for (non-public) subclass InnocuousForkJoinWorkerThread
-     * requires that we break quite a lot of encapsulation (via Unsafe)
-     * both here and in the subclass to access and set Thread fields.
+     * requires that we break quite a lot of encapsulation (via helper
+     * methods in ThreadLocalRandom) both here and in the subclass to
+     * access and set Thread fields.
      */
 
     final ForkJoinPool pool;                // the pool this thread works in
@@ -92,8 +93,8 @@
     ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
                          AccessControlContext acc) {
         super(threadGroup, null, "aForkJoinWorkerThread");
-        U.putObjectRelease(this, INHERITEDACCESSCONTROLCONTEXT, acc);
-        eraseThreadLocals(); // clear before registering
+        ThreadLocalRandom.setInheritedAccessControlContext(this, acc);
+        ThreadLocalRandom.eraseThreadLocals(this); // clear before registering
         this.pool = pool;
         this.workQueue = pool.registerWorker(this);
     }
@@ -171,37 +172,11 @@
     }
 
     /**
-     * Erases ThreadLocals by nulling out Thread maps.
-     */
-    final void eraseThreadLocals() {
-        U.putObject(this, THREADLOCALS, null);
-        U.putObject(this, INHERITABLETHREADLOCALS, null);
-    }
-
-    /**
      * Non-public hook method for InnocuousForkJoinWorkerThread.
      */
     void afterTopLevelExec() {
     }
 
-    // Set up to allow setting thread fields in constructor
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long THREADLOCALS;
-    private static final long INHERITABLETHREADLOCALS;
-    private static final long INHERITEDACCESSCONTROLCONTEXT;
-    static {
-        try {
-            THREADLOCALS = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocals"));
-            INHERITABLETHREADLOCALS = U.objectFieldOffset
-                (Thread.class.getDeclaredField("inheritableThreadLocals"));
-            INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
-                (Thread.class.getDeclaredField("inheritedAccessControlContext"));
-        } catch (ReflectiveOperationException e) {
-            throw new Error(e);
-        }
-    }
-
     /**
      * A worker thread that has no permissions, is not a member of any
      * user-defined ThreadGroup, and erases all ThreadLocals after
@@ -210,7 +185,7 @@
     static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
         /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
         private static final ThreadGroup innocuousThreadGroup =
-            createThreadGroup();
+            ThreadLocalRandom.createThreadGroup("InnocuousForkJoinWorkerThreadGroup");
 
         /** An AccessControlContext supporting no privileges */
         private static final AccessControlContext INNOCUOUS_ACC =
@@ -225,7 +200,7 @@
 
         @Override // to erase ThreadLocals
         void afterTopLevelExec() {
-            eraseThreadLocals();
+            ThreadLocalRandom.eraseThreadLocals(this);
         }
 
         @Override // to always report system loader
@@ -241,33 +216,5 @@
             throw new SecurityException("setContextClassLoader");
         }
 
-        /**
-         * Returns a new group with the system ThreadGroup (the
-         * topmost, parent-less group) as parent.  Uses Unsafe to
-         * traverse Thread.group and ThreadGroup.parent fields.
-         */
-        private static ThreadGroup createThreadGroup() {
-            try {
-                jdk.internal.misc.Unsafe u = jdk.internal.misc.Unsafe.getUnsafe();
-                long tg = u.objectFieldOffset
-                    (Thread.class.getDeclaredField("group"));
-                long gp = u.objectFieldOffset
-                    (ThreadGroup.class.getDeclaredField("parent"));
-                ThreadGroup group = (ThreadGroup)
-                    u.getObject(Thread.currentThread(), tg);
-                while (group != null) {
-                    ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
-                    if (parent == null)
-                        return new ThreadGroup(group,
-                                               "InnocuousForkJoinWorkerThreadGroup");
-                    group = parent;
-                }
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-            // fall through if null as cannot-happen safeguard
-            throw new Error("Cannot create ThreadGroup");
-        }
     }
-
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.concurrent.locks.LockSupport;
 
 /**
@@ -69,9 +71,6 @@
      * cancellation races. Sync control in the current design relies
      * on a "state" field updated via CAS to track completion, along
      * with a simple Treiber stack to hold waiting threads.
-     *
-     * Style note: As usual, we bypass overhead of using
-     * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
      */
 
     /**
@@ -163,9 +162,8 @@
     }
 
     public boolean cancel(boolean mayInterruptIfRunning) {
-        if (!(state == NEW &&
-              U.compareAndSwapInt(this, STATE, NEW,
-                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
+        if (!(state == NEW && STATE.compareAndSet
+              (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
             return false;
         try {    // in case call to interrupt throws exception
             if (mayInterruptIfRunning) {
@@ -174,7 +172,7 @@
                     if (t != null)
                         t.interrupt();
                 } finally { // final state
-                    U.putIntRelease(this, STATE, INTERRUPTED);
+                    STATE.setRelease(this, INTERRUPTED);
                 }
             }
         } finally {
@@ -228,9 +226,9 @@
      * @param v the value
      */
     protected void set(V v) {
-        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
             outcome = v;
-            U.putIntRelease(this, STATE, NORMAL); // final state
+            STATE.setRelease(this, NORMAL); // final state
             finishCompletion();
         }
     }
@@ -246,16 +244,16 @@
      * @param t the cause of failure
      */
     protected void setException(Throwable t) {
-        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
             outcome = t;
-            U.putIntRelease(this, STATE, EXCEPTIONAL); // final state
+            STATE.setRelease(this, EXCEPTIONAL); // final state
             finishCompletion();
         }
     }
 
     public void run() {
         if (state != NEW ||
-            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
             return;
         try {
             Callable<V> c = callable;
@@ -296,7 +294,7 @@
      */
     protected boolean runAndReset() {
         if (state != NEW ||
-            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
             return false;
         boolean ran = false;
         int s = state;
@@ -363,7 +361,7 @@
     private void finishCompletion() {
         // assert state > COMPLETING;
         for (WaitNode q; (q = waiters) != null;) {
-            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
+            if (WAITERS.weakCompareAndSetVolatile(this, q, null)) {
                 for (;;) {
                     Thread t = q.thread;
                     if (t != null) {
@@ -425,8 +423,7 @@
                 q = new WaitNode();
             }
             else if (!queued)
-                queued = U.compareAndSwapObject(this, WAITERS,
-                                                q.next = waiters, q);
+                queued = WAITERS.weakCompareAndSetVolatile(this, q.next = waiters, q);
             else if (timed) {
                 final long parkNanos;
                 if (startTime == 0L) { // first time
@@ -475,7 +472,7 @@
                         if (pred.thread == null) // check for race
                             continue retry;
                     }
-                    else if (!U.compareAndSwapObject(this, WAITERS, q, s))
+                    else if (!WAITERS.compareAndSet(this, q, s))
                         continue retry;
                 }
                 break;
@@ -483,19 +480,16 @@
         }
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long STATE;
-    private static final long RUNNER;
-    private static final long WAITERS;
+    // VarHandle mechanics
+    private static final VarHandle STATE;
+    private static final VarHandle RUNNER;
+    private static final VarHandle WAITERS;
     static {
         try {
-            STATE = U.objectFieldOffset
-                (FutureTask.class.getDeclaredField("state"));
-            RUNNER = U.objectFieldOffset
-                (FutureTask.class.getDeclaredField("runner"));
-            WAITERS = U.objectFieldOffset
-                (FutureTask.class.getDeclaredField("waiters"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(FutureTask.class, "state", int.class);
+            RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
+            WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
@@ -444,7 +446,7 @@
 
     /**
      * Queue nodes. Uses Object, not E, for items to allow forgetting
-     * them after use.  Relies heavily on Unsafe mechanics to minimize
+     * them after use.  Relies heavily on VarHandles to minimize
      * unnecessary ordering constraints: Writes that are intrinsically
      * ordered wrt other accesses or CASes use simple relaxed forms.
      */
@@ -456,12 +458,12 @@
 
         // CAS methods for fields
         final boolean casNext(Node cmp, Node val) {
-            return U.compareAndSwapObject(this, NEXT, cmp, val);
+            return NEXT.compareAndSet(this, cmp, val);
         }
 
         final boolean casItem(Object cmp, Object val) {
             // assert cmp == null || cmp.getClass() != Node.class;
-            return U.compareAndSwapObject(this, ITEM, cmp, val);
+            return ITEM.compareAndSet(this, cmp, val);
         }
 
         /**
@@ -469,7 +471,7 @@
          * only be seen after publication via casNext.
          */
         Node(Object item, boolean isData) {
-            U.putObject(this, ITEM, item); // relaxed write
+            ITEM.set(this, item); // relaxed write
             this.isData = isData;
         }
 
@@ -478,7 +480,7 @@
          * only after CASing head field, so uses relaxed write.
          */
         final void forgetNext() {
-            U.putObject(this, NEXT, this);
+            NEXT.set(this, this);
         }
 
         /**
@@ -491,8 +493,8 @@
          * else we don't care).
          */
         final void forgetContents() {
-            U.putObject(this, ITEM, this);
-            U.putObject(this, WAITER, null);
+            ITEM.set(this, this);
+            WAITER.set(this, null);
         }
 
         /**
@@ -537,19 +539,16 @@
 
         private static final long serialVersionUID = -3375979862319811754L;
 
-        // Unsafe mechanics
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long ITEM;
-        private static final long NEXT;
-        private static final long WAITER;
+        // VarHandle mechanics
+        private static final VarHandle ITEM;
+        private static final VarHandle NEXT;
+        private static final VarHandle WAITER;
         static {
             try {
-                ITEM = U.objectFieldOffset
-                    (Node.class.getDeclaredField("item"));
-                NEXT = U.objectFieldOffset
-                    (Node.class.getDeclaredField("next"));
-                WAITER = U.objectFieldOffset
-                    (Node.class.getDeclaredField("waiter"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                ITEM = l.findVarHandle(Node.class, "item", Object.class);
+                NEXT = l.findVarHandle(Node.class, "next", Node.class);
+                WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
@@ -567,15 +566,15 @@
 
     // CAS methods for fields
     private boolean casTail(Node cmp, Node val) {
-        return U.compareAndSwapObject(this, TAIL, cmp, val);
+        return TAIL.compareAndSet(this, cmp, val);
     }
 
     private boolean casHead(Node cmp, Node val) {
-        return U.compareAndSwapObject(this, HEAD, cmp, val);
+        return HEAD.compareAndSet(this, cmp, val);
     }
 
     private boolean casSweepVotes(int cmp, int val) {
-        return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
+        return SWEEPVOTES.compareAndSet(this, cmp, val);
     }
 
     /*
@@ -1562,20 +1561,19 @@
         }
     }
 
-    // Unsafe mechanics
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long HEAD;
-    private static final long TAIL;
-    private static final long SWEEPVOTES;
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    private static final VarHandle SWEEPVOTES;
     static {
         try {
-            HEAD = U.objectFieldOffset
-                (LinkedTransferQueue.class.getDeclaredField("head"));
-            TAIL = U.objectFieldOffset
-                (LinkedTransferQueue.class.getDeclaredField("tail"));
-            SWEEPVOTES = U.objectFieldOffset
-                (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(LinkedTransferQueue.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(LinkedTransferQueue.class, "tail",
+                                   Node.class);
+            SWEEPVOTES = l.findVarHandle(LinkedTransferQueue.class, "sweepVotes",
+                                         int.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.LockSupport;
 
@@ -221,7 +223,6 @@
  *   phaser.arriveAndDeregister();
  * }}</pre>
  *
- *
  * <p>To create a set of {@code n} tasks using a tree of phasers, you
  * could use code of the following form, assuming a Task class with a
  * constructor accepting a {@code Phaser} that it registers with upon
@@ -384,7 +385,7 @@
             int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
             if (unarrived <= 0)
                 throw new IllegalStateException(badArrive(s));
-            if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
+            if (STATE.compareAndSet(this, s, s-=adjust)) {
                 if (unarrived == 1) {
                     long n = s & PARTIES_MASK;  // base of next state
                     int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@@ -397,12 +398,12 @@
                             n |= nextUnarrived;
                         int nextPhase = (phase + 1) & MAX_PHASE;
                         n |= (long)nextPhase << PHASE_SHIFT;
-                        U.compareAndSwapLong(this, STATE, s, n);
+                        STATE.compareAndSet(this, s, n);
                         releaseWaiters(phase);
                     }
                     else if (nextUnarrived == 0) { // propagate deregistration
                         phase = parent.doArrive(ONE_DEREGISTER);
-                        U.compareAndSwapLong(this, STATE, s, s | EMPTY);
+                        STATE.compareAndSet(this, s, s | EMPTY);
                     }
                     else
                         phase = parent.doArrive(ONE_ARRIVAL);
@@ -437,13 +438,13 @@
                 if (parent == null || reconcileState() == s) {
                     if (unarrived == 0)             // wait out advance
                         root.internalAwaitAdvance(phase, null);
-                    else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
+                    else if (STATE.compareAndSet(this, s, s + adjust))
                         break;
                 }
             }
             else if (parent == null) {              // 1st root registration
                 long next = ((long)phase << PHASE_SHIFT) | adjust;
-                if (U.compareAndSwapLong(this, STATE, s, next))
+                if (STATE.compareAndSet(this, s, next))
                     break;
             }
             else {
@@ -455,8 +456,8 @@
                         // finish registration whenever parent registration
                         // succeeded, even when racing with termination,
                         // since these are part of the same "transaction".
-                        while (!U.compareAndSwapLong
-                               (this, STATE, s,
+                        while (!STATE.weakCompareAndSetVolatile
+                               (this, s,
                                 ((long)phase << PHASE_SHIFT) | adjust)) {
                             s = state;
                             phase = (int)(root.state >>> PHASE_SHIFT);
@@ -487,8 +488,8 @@
             // CAS to root phase with current parties, tripping unarrived
             while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
                    (int)(s >>> PHASE_SHIFT) &&
-                   !U.compareAndSwapLong
-                   (this, STATE, s,
+                   !STATE.weakCompareAndSetVolatile
+                   (this, s,
                     s = (((long)phase << PHASE_SHIFT) |
                          ((phase < 0) ? (s & COUNTS_MASK) :
                           (((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@@ -677,7 +678,7 @@
             int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
             if (unarrived <= 0)
                 throw new IllegalStateException(badArrive(s));
-            if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
+            if (STATE.compareAndSet(this, s, s -= ONE_ARRIVAL)) {
                 if (unarrived > 1)
                     return root.internalAwaitAdvance(phase, null);
                 if (root != this)
@@ -692,7 +693,7 @@
                     n |= nextUnarrived;
                 int nextPhase = (phase + 1) & MAX_PHASE;
                 n |= (long)nextPhase << PHASE_SHIFT;
-                if (!U.compareAndSwapLong(this, STATE, s, n))
+                if (!STATE.compareAndSet(this, s, n))
                     return (int)(state >>> PHASE_SHIFT); // terminated
                 releaseWaiters(phase);
                 return nextPhase;
@@ -808,7 +809,7 @@
         final Phaser root = this.root;
         long s;
         while ((s = root.state) >= 0) {
-            if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
+            if (STATE.compareAndSet(root, s, s | TERMINATION_BIT)) {
                 // signal all threads
                 releaseWaiters(0); // Waiters on evenQ
                 releaseWaiters(1); // Waiters on oddQ
@@ -1043,6 +1044,8 @@
                     node = new QNode(this, phase, false, false, 0L);
                     node.wasInterrupted = interrupted;
                 }
+                else
+                    Thread.onSpinWait();
             }
             else if (node.isReleasable()) // done or aborted
                 break;
@@ -1131,14 +1134,12 @@
         }
     }
 
-    // Unsafe mechanics
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long STATE;
+    // VarHandle mechanics
+    private static final VarHandle STATE;
     static {
         try {
-            STATE = U.objectFieldOffset
-                (Phaser.class.getDeclaredField("state"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(Phaser.class, "state", long.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Arrays;
 import java.util.Collection;
@@ -289,7 +291,7 @@
         lock.unlock(); // must release and then re-acquire main lock
         Object[] newArray = null;
         if (allocationSpinLock == 0 &&
-            U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
+            ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
             try {
                 int newCap = oldCap + ((oldCap < 64) ?
                                        (oldCap + 2) : // grow faster if small
@@ -1009,13 +1011,14 @@
         return new PBQSpliterator<E>(this, null, 0, -1);
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long ALLOCATIONSPINLOCK;
+    // VarHandle mechanics
+    private static final VarHandle ALLOCATIONSPINLOCK;
     static {
         try {
-            ALLOCATIONSPINLOCK = U.objectFieldOffset
-                (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            ALLOCATIONSPINLOCK = l.findVarHandle(PriorityBlockingQueue.class,
+                                                 "allocationSpinLock",
+                                                 int.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.locks.LockSupport;
@@ -866,7 +868,7 @@
 
     /** Subscriber for method consume */
     private static final class ConsumerSubscriber<T>
-            implements Flow.Subscriber<T> {
+        implements Flow.Subscriber<T> {
         final CompletableFuture<Void> status;
         final Consumer<? super T> consumer;
         Flow.Subscription subscription;
@@ -906,7 +908,7 @@
      */
     @SuppressWarnings("serial")
     static final class ConsumerTask<T> extends ForkJoinTask<Void>
-        implements Runnable {
+        implements Runnable, CompletableFuture.AsynchronousCompletionTask {
         final BufferedSubscription<T> consumer;
         ConsumerTask(BufferedSubscription<T> consumer) {
             this.consumer = consumer;
@@ -959,11 +961,9 @@
      * Blocking control relies on the "waiter" field. Producers set
      * the field before trying to block, but must then recheck (via
      * offer) before parking. Signalling then just unparks and clears
-     * waiter field. If the producer and consumer are both in the same
-     * ForkJoinPool, or consumers are running in commonPool, the
-     * producer attempts to help run consumer tasks that it forked
-     * before blocking.  To avoid potential cycles, only one level of
-     * helping is currently supported.
+     * waiter field. If the producer and/or consumer are using a
+     * ForkJoinPool, the producer attempts to help run consumer tasks
+     * via ForkJoinPool.helpAsyncBlocker before blocking.
      *
      * This class uses @Contended and heuristic field declaration
      * ordering to reduce false-sharing-based memory contention among
@@ -983,7 +983,6 @@
         volatile long demand;              // # unfilled requests
         int maxCapacity;                   // reduced on OOME
         int putStat;                       // offer result for ManagedBlocker
-        int helpDepth;                     // nested helping depth (at most 1)
         volatile int ctl;                  // atomic run state flags
         volatile int head;                 // next position to take
         int tail;                          // next position to put
@@ -1077,7 +1076,7 @@
                 alloc = true;
             }
             else {
-                U.fullFence();                   // recheck
+                VarHandle.fullFence();           // recheck
                 int h = head, t = tail, size = t + 1 - h;
                 if (cap >= size) {
                     a[(cap - 1) & t] = item;
@@ -1116,10 +1115,10 @@
                         if (a != null && cap > 0) {
                             int mask = cap - 1;
                             for (int j = head; j != t; ++j) {
-                                long k = ((long)(j & mask) << ASHIFT) + ABASE;
-                                Object x = U.getObjectVolatile(a, k);
+                                int k = j & mask;
+                                Object x = QA.getAcquire(a, k);
                                 if (x != null && // races with consumer
-                                    U.compareAndSwapObject(a, k, x, null))
+                                    QA.compareAndSet(a, k, x, null))
                                     newArray[j & newMask] = x;
                             }
                         }
@@ -1136,28 +1135,20 @@
          * initial offer return 0.
          */
         final int submit(T item) {
-            int stat; Executor e; ForkJoinWorkerThread w;
-            if ((stat = offer(item)) == 0 && helpDepth == 0 &&
-                ((e = executor) instanceof ForkJoinPool)) {
-                helpDepth = 1;
-                Thread thread = Thread.currentThread();
-                if ((thread instanceof ForkJoinWorkerThread) &&
-                    ((w = (ForkJoinWorkerThread)thread)).getPool() == e)
-                    stat = internalHelpConsume(w.workQueue, item);
-                else if (e == ForkJoinPool.commonPool())
-                    stat = externalHelpConsume
-                        (ForkJoinPool.commonSubmitterQueue(), item);
-                helpDepth = 0;
-            }
-            if (stat == 0 && (stat = offer(item)) == 0) {
+            int stat;
+            if ((stat = offer(item)) == 0) {
                 putItem = item;
                 timeout = 0L;
-                try {
-                    ForkJoinPool.managedBlock(this);
-                } catch (InterruptedException ie) {
-                    timeout = INTERRUPTED;
+                putStat = 0;
+                ForkJoinPool.helpAsyncBlocker(executor, this);
+                if ((stat = putStat) == 0) {
+                    try {
+                        ForkJoinPool.managedBlock(this);
+                    } catch (InterruptedException ie) {
+                        timeout = INTERRUPTED;
+                    }
+                    stat = putStat;
                 }
-                stat = putStat;
                 if (timeout < 0L)
                     Thread.currentThread().interrupt();
             }
@@ -1165,71 +1156,22 @@
         }
 
         /**
-         * Tries helping for FJ submitter.
-         */
-        private int internalHelpConsume(ForkJoinPool.WorkQueue w, T item) {
-            int stat = 0;
-            if (w != null) {
-                ForkJoinTask<?> t;
-                while ((t = w.peek()) != null && (t instanceof ConsumerTask)) {
-                    if ((stat = offer(item)) != 0 || !w.tryUnpush(t))
-                        break;
-                    ((ConsumerTask<?>)t).consumer.consume();
-                }
-            }
-            return stat;
-        }
-
-        /**
-         * Tries helping for non-FJ submitter.
-         */
-        private int externalHelpConsume(ForkJoinPool.WorkQueue w, T item) {
-            int stat = 0;
-            if (w != null) {
-                ForkJoinTask<?> t;
-                while ((t = w.peek()) != null && (t instanceof ConsumerTask)) {
-                    if ((stat = offer(item)) != 0 || !w.trySharedUnpush(t))
-                        break;
-                    ((ConsumerTask<?>)t).consumer.consume();
-                }
-            }
-            return stat;
-        }
-
-        /**
          * Timeout version; similar to submit.
          */
         final int timedOffer(T item, long nanos) {
-            int stat; Executor e;
-            if ((stat = offer(item)) == 0 && helpDepth == 0 &&
-                ((e = executor) instanceof ForkJoinPool)) {
-                Thread thread = Thread.currentThread();
-                if (((thread instanceof ForkJoinWorkerThread) &&
-                     ((ForkJoinWorkerThread)thread).getPool() == e) ||
-                    e == ForkJoinPool.commonPool()) {
-                    helpDepth = 1;
-                    ForkJoinTask<?> t;
-                    long deadline = System.nanoTime() + nanos;
-                    while ((t = ForkJoinTask.peekNextLocalTask()) != null &&
-                           (t instanceof ConsumerTask)) {
-                        if ((stat = offer(item)) != 0 ||
-                            (nanos = deadline - System.nanoTime()) <= 0L ||
-                            !t.tryUnfork())
-                            break;
-                        ((ConsumerTask<?>)t).consumer.consume();
+            int stat;
+            if ((stat = offer(item)) == 0 && (timeout = nanos) > 0L) {
+                putItem = item;
+                putStat = 0;
+                ForkJoinPool.helpAsyncBlocker(executor, this);
+                if ((stat = putStat) == 0) {
+                    try {
+                        ForkJoinPool.managedBlock(this);
+                    } catch (InterruptedException ie) {
+                        timeout = INTERRUPTED;
                     }
-                    helpDepth = 0;
+                    stat = putStat;
                 }
-            }
-            if (stat == 0 && (stat = offer(item)) == 0 &&
-                (timeout = nanos) > 0L) {
-                putItem = item;
-                try {
-                    ForkJoinPool.managedBlock(this);
-                } catch (InterruptedException ie) {
-                    timeout = INTERRUPTED;
-                }
-                stat = putStat;
                 if (timeout < 0L)
                     Thread.currentThread().interrupt();
             }
@@ -1249,22 +1191,20 @@
                 }
                 else if ((c & ACTIVE) != 0) { // ensure keep-alive
                     if ((c & CONSUME) != 0 ||
-                        U.compareAndSwapInt(this, CTL, c,
-                                            c | CONSUME))
+                        CTL.compareAndSet(this, c, c | CONSUME))
                         break;
                 }
                 else if (demand == 0L || tail == head)
                     break;
-                else if (U.compareAndSwapInt(this, CTL, c,
-                                             c | (ACTIVE | CONSUME))) {
+                else if (CTL.compareAndSet(this, c, c | (ACTIVE | CONSUME))) {
                     try {
                         e.execute(new ConsumerTask<T>(this));
                         break;
                     } catch (RuntimeException | Error ex) { // back out
                         do {} while (((c = ctl) & DISABLED) == 0 &&
                                      (c & ACTIVE) != 0 &&
-                                     !U.compareAndSwapInt(this, CTL, c,
-                                                          c & ~ACTIVE));
+                                     !CTL.weakCompareAndSetVolatile
+                                     (this, c, c & ~ACTIVE));
                         throw ex;
                     }
                 }
@@ -1300,10 +1240,10 @@
                     break;
                 else if ((c & ACTIVE) != 0) {
                     pendingError = ex;
-                    if (U.compareAndSwapInt(this, CTL, c, c | ERROR))
+                    if (CTL.compareAndSet(this, c, c | ERROR))
                         break; // cause consumer task to exit
                 }
-                else if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
+                else if (CTL.compareAndSet(this, c, DISABLED)) {
                     Flow.Subscriber<? super T> s = subscriber;
                     if (s != null && ex != null) {
                         try {
@@ -1330,7 +1270,7 @@
                     for (int c;;) {
                         if ((c = ctl) == DISABLED || (c & ACTIVE) == 0)
                             break;
-                        if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE)) {
+                        if (CTL.compareAndSet(this, c, c & ~ACTIVE)) {
                             onError(ex);
                             break;
                         }
@@ -1343,8 +1283,8 @@
             for (int c;;) {
                 if ((c = ctl) == DISABLED)
                     break;
-                if (U.compareAndSwapInt(this, CTL, c,
-                                        c | (ACTIVE | CONSUME | COMPLETE))) {
+                if (CTL.compareAndSet(this, c,
+                                      c | (ACTIVE | CONSUME | COMPLETE))) {
                     if ((c & ACTIVE) == 0)
                         startOrDisable();
                     break;
@@ -1356,8 +1296,8 @@
             for (int c;;) {
                 if ((c = ctl) == DISABLED)
                     break;
-                if (U.compareAndSwapInt(this, CTL, c,
-                                        c | (ACTIVE | CONSUME | SUBSCRIBE))) {
+                if (CTL.compareAndSet(this, c,
+                                      c | (ACTIVE | CONSUME | SUBSCRIBE))) {
                     if ((c & ACTIVE) == 0)
                         startOrDisable();
                     break;
@@ -1375,11 +1315,11 @@
                 if ((c = ctl) == DISABLED)
                     break;
                 else if ((c & ACTIVE) != 0) {
-                    if (U.compareAndSwapInt(this, CTL, c,
-                                            c | (CONSUME | ERROR)))
+                    if (CTL.compareAndSet(this, c,
+                                          c | (CONSUME | ERROR)))
                         break;
                 }
-                else if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
+                else if (CTL.compareAndSet(this, c, DISABLED)) {
                     detach();
                     break;
                 }
@@ -1395,19 +1335,18 @@
                     long prev = demand, d;
                     if ((d = prev + n) < prev) // saturate
                         d = Long.MAX_VALUE;
-                    if (U.compareAndSwapLong(this, DEMAND, prev, d)) {
+                    if (DEMAND.compareAndSet(this, prev, d)) {
                         for (int c, h;;) {
                             if ((c = ctl) == DISABLED)
                                 break;
                             else if ((c & ACTIVE) != 0) {
                                 if ((c & CONSUME) != 0 ||
-                                    U.compareAndSwapInt(this, CTL, c,
-                                                        c | CONSUME))
+                                    CTL.compareAndSet(this, c, c | CONSUME))
                                     break;
                             }
                             else if ((h = head) != tail) {
-                                if (U.compareAndSwapInt(this, CTL, c,
-                                                        c | (ACTIVE|CONSUME))) {
+                                if (CTL.compareAndSet(this, c,
+                                                      c | (ACTIVE|CONSUME))) {
                                     startOrDisable();
                                     break;
                                 }
@@ -1476,16 +1415,14 @@
             if ((s = subscriber) != null) {           // else disabled
                 for (;;) {
                     long d = demand;
-                    int c; Object[] a; int n; long i; Object x; Thread w;
+                    int c; Object[] a; int n, i; Object x; Thread w;
                     if (((c = ctl) & (ERROR | SUBSCRIBE | DISABLED)) != 0) {
                         if (!checkControl(s, c))
                             break;
                     }
                     else if ((a = array) == null || h == tail ||
                              (n = a.length) == 0 ||
-                             (x = U.getObjectVolatile
-                              (a, (i = ((long)((n - 1) & h) << ASHIFT) + ABASE)))
-                             == null) {
+                             (x = QA.getAcquire(a, i = (n - 1) & h)) == null) {
                         if (!checkEmpty(s, c))
                             break;
                     }
@@ -1494,10 +1431,10 @@
                             break;
                     }
                     else if (((c & CONSUME) != 0 ||
-                              U.compareAndSwapInt(this, CTL, c, c | CONSUME)) &&
-                             U.compareAndSwapObject(a, i, x, null)) {
-                        U.putIntRelease(this, HEAD, ++h);
-                        U.getAndAddLong(this, DEMAND, -1L);
+                              CTL.compareAndSet(this, c, c | CONSUME)) &&
+                             QA.compareAndSet(a, i, x, null)) {
+                        HEAD.setRelease(this, ++h);
+                        DEMAND.getAndAdd(this, -1L);
                         if ((w = waiter) != null)
                             signalWaiter(w);
                         try {
@@ -1528,7 +1465,7 @@
                 }
             }
             else if ((c & SUBSCRIBE) != 0) {
-                if (U.compareAndSwapInt(this, CTL, c, c & ~SUBSCRIBE)) {
+                if (CTL.compareAndSet(this, c, c & ~SUBSCRIBE)) {
                     try {
                         if (s != null)
                             s.onSubscribe(this);
@@ -1551,9 +1488,9 @@
             boolean stat = true;
             if (head == tail) {
                 if ((c & CONSUME) != 0)
-                    U.compareAndSwapInt(this, CTL, c, c & ~CONSUME);
+                    CTL.compareAndSet(this, c, c & ~CONSUME);
                 else if ((c & COMPLETE) != 0) {
-                    if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
+                    if (CTL.compareAndSet(this, c, DISABLED)) {
                         try {
                             if (s != null)
                                 s.onComplete();
@@ -1561,7 +1498,7 @@
                         }
                     }
                 }
-                else if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE))
+                else if (CTL.compareAndSet(this, c, c & ~ACTIVE))
                     stat = false;
             }
             return stat;
@@ -1574,8 +1511,8 @@
             boolean stat = true;
             if (demand == 0L) {
                 if ((c & CONSUME) != 0)
-                    U.compareAndSwapInt(this, CTL, c, c & ~CONSUME);
-                else if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE))
+                    CTL.compareAndSet(this, c, c & ~CONSUME);
+                else if (CTL.compareAndSet(this, c, c & ~ACTIVE))
                     stat = false;
             }
             return stat;
@@ -1595,31 +1532,25 @@
             onError(ex);
         }
 
-        // Unsafe mechanics
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long CTL;
-        private static final long TAIL;
-        private static final long HEAD;
-        private static final long DEMAND;
-        private static final int ABASE;
-        private static final int ASHIFT;
+        // VarHandle mechanics
+        private static final VarHandle CTL;
+        private static final VarHandle TAIL;
+        private static final VarHandle HEAD;
+        private static final VarHandle DEMAND;
+        private static final VarHandle QA;
 
         static {
             try {
-                CTL = U.objectFieldOffset
-                    (BufferedSubscription.class.getDeclaredField("ctl"));
-                TAIL = U.objectFieldOffset
-                    (BufferedSubscription.class.getDeclaredField("tail"));
-                HEAD = U.objectFieldOffset
-                    (BufferedSubscription.class.getDeclaredField("head"));
-                DEMAND = U.objectFieldOffset
-                    (BufferedSubscription.class.getDeclaredField("demand"));
-
-                ABASE = U.arrayBaseOffset(Object[].class);
-                int scale = U.arrayIndexScale(Object[].class);
-                if ((scale & (scale - 1)) != 0)
-                    throw new Error("data type scale not a power of two");
-                ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                CTL = l.findVarHandle(BufferedSubscription.class, "ctl",
+                                      int.class);
+                TAIL = l.findVarHandle(BufferedSubscription.class, "tail",
+                                       int.class);
+                HEAD = l.findVarHandle(BufferedSubscription.class, "head",
+                                       int.class);
+                DEMAND = l.findVarHandle(BufferedSubscription.class, "demand",
+                                         long.class);
+                QA = MethodHandles.arrayElementVarHandle(Object[].class);
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java	Wed Jul 05 22:00:06 2017 +0200
@@ -36,6 +36,8 @@
 
 package java.util.concurrent;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.AbstractQueue;
 import java.util.Collection;
 import java.util.Collections;
@@ -247,7 +249,7 @@
 
             boolean casNext(SNode cmp, SNode val) {
                 return cmp == next &&
-                    U.compareAndSwapObject(this, NEXT, cmp, val);
+                    SNEXT.compareAndSet(this, cmp, val);
             }
 
             /**
@@ -260,7 +262,7 @@
              */
             boolean tryMatch(SNode s) {
                 if (match == null &&
-                    U.compareAndSwapObject(this, MATCH, null, s)) {
+                    SMATCH.compareAndSet(this, null, s)) {
                     Thread w = waiter;
                     if (w != null) {    // waiters need at most one unpark
                         waiter = null;
@@ -275,24 +277,21 @@
              * Tries to cancel a wait by matching node to itself.
              */
             void tryCancel() {
-                U.compareAndSwapObject(this, MATCH, null, this);
+                SMATCH.compareAndSet(this, null, this);
             }
 
             boolean isCancelled() {
                 return match == this;
             }
 
-            // Unsafe mechanics
-            private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-            private static final long MATCH;
-            private static final long NEXT;
-
+            // VarHandle mechanics
+            private static final VarHandle SMATCH;
+            private static final VarHandle SNEXT;
             static {
                 try {
-                    MATCH = U.objectFieldOffset
-                        (SNode.class.getDeclaredField("match"));
-                    NEXT = U.objectFieldOffset
-                        (SNode.class.getDeclaredField("next"));
+                    MethodHandles.Lookup l = MethodHandles.lookup();
+                    SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
+                    SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
                 } catch (ReflectiveOperationException e) {
                     throw new Error(e);
                 }
@@ -304,7 +303,7 @@
 
         boolean casHead(SNode h, SNode nh) {
             return h == head &&
-                U.compareAndSwapObject(this, HEAD, h, nh);
+                SHEAD.compareAndSet(this, h, nh);
         }
 
         /**
@@ -451,8 +450,10 @@
                         continue;
                     }
                 }
-                if (spins > 0)
+                if (spins > 0) {
+                    Thread.onSpinWait();
                     spins = shouldSpin(s) ? (spins - 1) : 0;
+                }
                 else if (s.waiter == null)
                     s.waiter = w; // establish waiter so can park next iter
                 else if (!timed)
@@ -508,13 +509,12 @@
             }
         }
 
-        // Unsafe mechanics
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long HEAD;
+        // VarHandle mechanics
+        private static final VarHandle SHEAD;
         static {
             try {
-                HEAD = U.objectFieldOffset
-                    (TransferStack.class.getDeclaredField("head"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
@@ -546,19 +546,19 @@
 
             boolean casNext(QNode cmp, QNode val) {
                 return next == cmp &&
-                    U.compareAndSwapObject(this, NEXT, cmp, val);
+                    QNEXT.compareAndSet(this, cmp, val);
             }
 
             boolean casItem(Object cmp, Object val) {
                 return item == cmp &&
-                    U.compareAndSwapObject(this, ITEM, cmp, val);
+                    QITEM.compareAndSet(this, cmp, val);
             }
 
             /**
              * Tries to cancel by CAS'ing ref to this as item.
              */
             void tryCancel(Object cmp) {
-                U.compareAndSwapObject(this, ITEM, cmp, this);
+                QITEM.compareAndSet(this, cmp, this);
             }
 
             boolean isCancelled() {
@@ -574,17 +574,14 @@
                 return next == this;
             }
 
-            // Unsafe mechanics
-            private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-            private static final long ITEM;
-            private static final long NEXT;
-
+            // VarHandle mechanics
+            private static final VarHandle QITEM;
+            private static final VarHandle QNEXT;
             static {
                 try {
-                    ITEM = U.objectFieldOffset
-                        (QNode.class.getDeclaredField("item"));
-                    NEXT = U.objectFieldOffset
-                        (QNode.class.getDeclaredField("next"));
+                    MethodHandles.Lookup l = MethodHandles.lookup();
+                    QITEM = l.findVarHandle(QNode.class, "item", Object.class);
+                    QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
                 } catch (ReflectiveOperationException e) {
                     throw new Error(e);
                 }
@@ -614,7 +611,7 @@
          */
         void advanceHead(QNode h, QNode nh) {
             if (h == head &&
-                U.compareAndSwapObject(this, HEAD, h, nh))
+                QHEAD.compareAndSet(this, h, nh))
                 h.next = h; // forget old next
         }
 
@@ -623,7 +620,7 @@
          */
         void advanceTail(QNode t, QNode nt) {
             if (tail == t)
-                U.compareAndSwapObject(this, TAIL, t, nt);
+                QTAIL.compareAndSet(this, t, nt);
         }
 
         /**
@@ -631,7 +628,7 @@
          */
         boolean casCleanMe(QNode cmp, QNode val) {
             return cleanMe == cmp &&
-                U.compareAndSwapObject(this, CLEANME, cmp, val);
+                QCLEANME.compareAndSet(this, cmp, val);
         }
 
         /**
@@ -752,8 +749,10 @@
                         continue;
                     }
                 }
-                if (spins > 0)
+                if (spins > 0) {
                     --spins;
+                    Thread.onSpinWait();
+                }
                 else if (s.waiter == null)
                     s.waiter = w;
                 else if (!timed)
@@ -817,18 +816,19 @@
             }
         }
 
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long HEAD;
-        private static final long TAIL;
-        private static final long CLEANME;
+        // VarHandle mechanics
+        private static final VarHandle QHEAD;
+        private static final VarHandle QTAIL;
+        private static final VarHandle QCLEANME;
         static {
             try {
-                HEAD = U.objectFieldOffset
-                    (TransferQueue.class.getDeclaredField("head"));
-                TAIL = U.objectFieldOffset
-                    (TransferQueue.class.getDeclaredField("tail"));
-                CLEANME = U.objectFieldOffset
-                    (TransferQueue.class.getDeclaredField("cleanMe"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                QHEAD = l.findVarHandle(TransferQueue.class, "head",
+                                        QNode.class);
+                QTAIL = l.findVarHandle(TransferQueue.class, "tail",
+                                        QNode.class);
+                QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
+                                           QNode.class);
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Wed Jul 05 22:00:06 2017 +0200
@@ -36,6 +36,7 @@
 package java.util.concurrent;
 
 import java.io.ObjectStreamField;
+import java.security.AccessControlContext;
 import java.util.Random;
 import java.util.Spliterator;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -47,6 +48,7 @@
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
 import java.util.stream.StreamSupport;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A random number generator isolated to the current thread.  Like the
@@ -95,7 +97,9 @@
      * ThreadLocalRandom sequence.  The dual use is a marriage of
      * convenience, but is a simple and efficient way of reducing
      * application-level overhead and footprint of most concurrent
-     * programs.
+     * programs. Even more opportunistically, we also define here
+     * other package-private utilities that access Thread class
+     * fields.
      *
      * Even though this class subclasses java.util.Random, it uses the
      * same basic algorithm as java.util.SplittableRandom.  (See its
@@ -958,6 +962,49 @@
         return r;
     }
 
+    // Support for other package-private ThreadLocal access
+
+    /**
+     * Erases ThreadLocals by nulling out Thread maps.
+     */
+    static final void eraseThreadLocals(Thread thread) {
+        U.putObject(thread, THREADLOCALS, null);
+        U.putObject(thread, INHERITABLETHREADLOCALS, null);
+    }
+
+    static final void setInheritedAccessControlContext(Thread thread,
+                                                       AccessControlContext acc) {
+        U.putObjectRelease(thread, INHERITEDACCESSCONTROLCONTEXT, acc);
+    }
+
+    /**
+     * Returns a new group with the system ThreadGroup (the
+     * topmost, parent-less group) as parent.  Uses Unsafe to
+     * traverse Thread.group and ThreadGroup.parent fields.
+     */
+    static final ThreadGroup createThreadGroup(String name) {
+        if (name == null)
+            throw new NullPointerException();
+        try {
+            long tg = U.objectFieldOffset
+                (Thread.class.getDeclaredField("group"));
+            long gp = U.objectFieldOffset
+                (ThreadGroup.class.getDeclaredField("parent"));
+            ThreadGroup group = (ThreadGroup)
+                U.getObject(Thread.currentThread(), tg);
+            while (group != null) {
+                ThreadGroup parent = (ThreadGroup)U.getObject(group, gp);
+                if (parent == null)
+                    return new ThreadGroup(group, name);
+                group = parent;
+            }
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+        // fall through if null as cannot-happen safeguard
+        throw new Error("Cannot create ThreadGroup");
+    }
+
     // Serialization support
 
     private static final long serialVersionUID = -5851777807851030925L;
@@ -1022,10 +1069,13 @@
     static final String BAD_SIZE  = "size must be non-negative";
 
     // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+    private static final Unsafe U = Unsafe.getUnsafe();
     private static final long SEED;
     private static final long PROBE;
     private static final long SECONDARY;
+    private static final long THREADLOCALS;
+    private static final long INHERITABLETHREADLOCALS;
+    private static final long INHERITEDACCESSCONTROLCONTEXT;
     static {
         try {
             SEED = U.objectFieldOffset
@@ -1034,6 +1084,12 @@
                 (Thread.class.getDeclaredField("threadLocalRandomProbe"));
             SECONDARY = U.objectFieldOffset
                 (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+            THREADLOCALS = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocals"));
+            INHERITABLETHREADLOCALS = U.objectFieldOffset
+                (Thread.class.getDeclaredField("inheritableThreadLocals"));
+            INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
+                (Thread.class.getDeclaredField("inheritedAccessControlContext"));
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,27 +35,26 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
 /**
  * A {@code boolean} value that may be updated atomically. See the
- * {@link java.util.concurrent.atomic} package specification for
- * description of the properties of atomic variables. An
- * {@code AtomicBoolean} is used in applications such as atomically
- * updated flags, and cannot be used as a replacement for a
- * {@link java.lang.Boolean}.
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicBoolean} is used in
+ * applications such as atomically updated flags, and cannot be used
+ * as a replacement for a {@link java.lang.Boolean}.
  *
  * @since 1.5
  * @author Doug Lea
  */
 public class AtomicBoolean implements java.io.Serializable {
     private static final long serialVersionUID = 4654671469794556979L;
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long VALUE;
-
+    private static final VarHandle VALUE;
     static {
         try {
-            VALUE = U.objectFieldOffset
-                (AtomicBoolean.class.getDeclaredField("value"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
@@ -79,7 +78,8 @@
     }
 
     /**
-     * Returns the current value.
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      *
      * @return the current value
      */
@@ -88,40 +88,39 @@
     }
 
     /**
-     * Atomically sets the value to the given updated value
-     * if the current value {@code ==} the expected value.
+     * Atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
      *
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful. False return indicates that
      * the actual value was not equal to the expected value.
      */
-    public final boolean compareAndSet(boolean expect, boolean update) {
-        return U.compareAndSwapInt(this, VALUE,
-                                   (expect ? 1 : 0),
-                                   (update ? 1 : 0));
+    public final boolean compareAndSet(boolean expectedValue, boolean newValue) {
+        return VALUE.compareAndSet(this,
+                                   (expectedValue ? 1 : 0),
+                                   (newValue ? 1 : 0));
     }
 
     /**
-     * Atomically sets the value to the given updated value
-     * if the current value {@code ==} the expected value.
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
      *
-     * <p><a href="package-summary.html#weakCompareAndSet">May fail
-     * spuriously and does not provide ordering guarantees</a>, so is
-     * only rarely an appropriate alternative to {@code compareAndSet}.
-     *
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful
      */
-    public boolean weakCompareAndSet(boolean expect, boolean update) {
-        return U.compareAndSwapInt(this, VALUE,
-                                   (expect ? 1 : 0),
-                                   (update ? 1 : 0));
+    public boolean weakCompareAndSet(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSet(this,
+                                       (expectedValue ? 1 : 0),
+                                       (newValue ? 1 : 0));
     }
 
     /**
-     * Unconditionally sets to the given value.
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
      *
      * @param newValue the new value
      */
@@ -130,17 +129,19 @@
     }
 
     /**
-     * Eventually sets to the given value.
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
      *
      * @param newValue the new value
      * @since 1.6
      */
     public final void lazySet(boolean newValue) {
-        U.putIntRelease(this, VALUE, (newValue ? 1 : 0));
+        VALUE.setRelease(this, (newValue ? 1 : 0));
     }
 
     /**
-     * Atomically sets to the given value and returns the previous value.
+     * Atomically sets the value to {@code newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
      *
      * @param newValue the new value
      * @return the previous value
@@ -161,4 +162,178 @@
         return Boolean.toString(get());
     }
 
+    // jdk9
+
+    /**
+     * Returns the current value, with memory semantics of reading as
+     * if the variable was declared non-{@code volatile}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final boolean getPlain() {
+        return (int)VALUE.get(this) != 0;
+    }
+
+    /**
+     * Sets the value to {@code newValue}, with memory semantics
+     * of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(boolean newValue) {
+        VALUE.set(this, newValue ? 1 : 0);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final boolean getOpaque() {
+        return (int)VALUE.getOpaque(this) != 0;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(boolean newValue) {
+        VALUE.setOpaque(this, newValue ? 1 : 0);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final boolean getAcquire() {
+        return (int)VALUE.getAcquire(this) != 0;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(boolean newValue) {
+        VALUE.setRelease(this, newValue ? 1 : 0);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final boolean compareAndExchange(boolean expectedValue, boolean newValue) {
+        return (int)VALUE.compareAndExchange(this,
+                                             (expectedValue ? 1 : 0),
+                                             (newValue ? 1 : 0)) != 0;
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final boolean compareAndExchangeAcquire(boolean expectedValue, boolean newValue) {
+        return (int)VALUE.compareAndExchangeAcquire(this,
+                                                    (expectedValue ? 1 : 0),
+                                                    (newValue ? 1 : 0)) != 0;
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final boolean compareAndExchangeRelease(boolean expectedValue, boolean newValue) {
+        return (int)VALUE.compareAndExchangeRelease(this,
+                                                    (expectedValue ? 1 : 0),
+                                                    (newValue ? 1 : 0)) != 0;
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if the current
+     * value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetVolatile}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSetVolatile(this,
+                                               (expectedValue ? 1 : 0),
+                                               (newValue ? 1 : 0));
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if the current
+     * value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSetAcquire(this,
+                                              (expectedValue ? 1 : 0),
+                                              (newValue ? 1 : 0));
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if the current
+     * value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSetRelease(this,
+                                              (expectedValue ? 1 : 0),
+                                              (newValue ? 1 : 0));
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,18 +35,18 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.VarHandle;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntUnaryOperator;
 
 /**
  * An {@code int} value that may be updated atomically.  See the
- * {@link java.util.concurrent.atomic} package specification for
- * description of the properties of atomic variables. An
- * {@code AtomicInteger} is used in applications such as atomically
- * incremented counters, and cannot be used as a replacement for an
- * {@link java.lang.Integer}. However, this class does extend
- * {@code Number} to allow uniform access by tools and utilities that
- * deal with numerically-based classes.
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicInteger} is used in
+ * applications such as atomically incremented counters, and cannot be
+ * used as a replacement for an {@link java.lang.Integer}. However,
+ * this class does extend {@code Number} to allow uniform access by
+ * tools and utilities that deal with numerically-based classes.
  *
  * @since 1.5
  * @author Doug Lea
@@ -54,6 +54,10 @@
 public class AtomicInteger extends Number implements java.io.Serializable {
     private static final long serialVersionUID = 6214790243416807050L;
 
+    /*
+     * This class intended to be implemented using VarHandles, but there
+     * are unresolved cyclic startup dependencies.
+     */
     private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
     private static final long VALUE;
 
@@ -84,7 +88,8 @@
     }
 
     /**
-     * Gets the current value.
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      *
      * @return the current value
      */
@@ -93,7 +98,8 @@
     }
 
     /**
-     * Sets to the given value.
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
      *
      * @param newValue the new value
      */
@@ -102,7 +108,8 @@
     }
 
     /**
-     * Eventually sets to the given value.
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
      *
      * @param newValue the new value
      * @since 1.6
@@ -112,7 +119,8 @@
     }
 
     /**
-     * Atomically sets to the given value and returns the old value.
+     * Atomically sets the value to {@code newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
      *
      * @param newValue the new value
      * @return the previous value
@@ -122,36 +130,37 @@
     }
 
     /**
-     * Atomically sets the value to the given updated value
-     * if the current value {@code ==} the expected value.
+     * Atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
      *
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful. False return indicates that
      * the actual value was not equal to the expected value.
      */
-    public final boolean compareAndSet(int expect, int update) {
-        return U.compareAndSwapInt(this, VALUE, expect, update);
+    public final boolean compareAndSet(int expectedValue, int newValue) {
+        return U.compareAndSwapInt(this, VALUE, expectedValue, newValue);
     }
 
     /**
-     * Atomically sets the value to the given updated value
-     * if the current value {@code ==} the expected value.
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
      *
-     * <p><a href="package-summary.html#weakCompareAndSet">May fail
-     * spuriously and does not provide ordering guarantees</a>, so is
-     * only rarely an appropriate alternative to {@code compareAndSet}.
-     *
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful
      */
-    public final boolean weakCompareAndSet(int expect, int update) {
-        return U.compareAndSwapInt(this, VALUE, expect, update);
+    public final boolean weakCompareAndSet(int expectedValue, int newValue) {
+        return U.weakCompareAndSwapInt(this, VALUE, expectedValue, newValue);
     }
 
     /**
-     * Atomically increments by one the current value.
+     * Atomically increments the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(1)}.
      *
      * @return the previous value
      */
@@ -160,7 +169,10 @@
     }
 
     /**
-     * Atomically decrements by one the current value.
+     * Atomically decrements the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(-1)}.
      *
      * @return the previous value
      */
@@ -169,7 +181,8 @@
     }
 
     /**
-     * Atomically adds the given value to the current value.
+     * Atomically adds the given value to the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
      *
      * @param delta the value to add
      * @return the previous value
@@ -179,7 +192,10 @@
     }
 
     /**
-     * Atomically increments by one the current value.
+     * Atomically increments the current value,
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
+     *
+     * <p>Equivalent to {@code addAndGet(1)}.
      *
      * @return the updated value
      */
@@ -188,7 +204,10 @@
     }
 
     /**
-     * Atomically decrements by one the current value.
+     * Atomically decrements the current value,
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
+     *
+     * <p>Equivalent to {@code addAndGet(-1)}.
      *
      * @return the updated value
      */
@@ -197,7 +216,8 @@
     }
 
     /**
-     * Atomically adds the given value to the current value.
+     * Atomically adds the given value to the current value,
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
      *
      * @param delta the value to add
      * @return the updated value
@@ -217,12 +237,14 @@
      * @since 1.8
      */
     public final int getAndUpdate(IntUnaryOperator updateFunction) {
-        int prev, next;
-        do {
-            prev = get();
-            next = updateFunction.applyAsInt(prev);
-        } while (!compareAndSet(prev, next));
-        return prev;
+        int prev = get(), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsInt(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -236,12 +258,14 @@
      * @since 1.8
      */
     public final int updateAndGet(IntUnaryOperator updateFunction) {
-        int prev, next;
-        do {
-            prev = get();
-            next = updateFunction.applyAsInt(prev);
-        } while (!compareAndSet(prev, next));
-        return next;
+        int prev = get(), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsInt(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -260,12 +284,14 @@
      */
     public final int getAndAccumulate(int x,
                                       IntBinaryOperator accumulatorFunction) {
-        int prev, next;
-        do {
-            prev = get();
-            next = accumulatorFunction.applyAsInt(prev, x);
-        } while (!compareAndSet(prev, next));
-        return prev;
+        int prev = get(), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsInt(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -284,12 +310,14 @@
      */
     public final int accumulateAndGet(int x,
                                       IntBinaryOperator accumulatorFunction) {
-        int prev, next;
-        do {
-            prev = get();
-            next = accumulatorFunction.applyAsInt(prev, x);
-        } while (!compareAndSet(prev, next));
-        return next;
+        int prev = get(), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsInt(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -301,7 +329,10 @@
     }
 
     /**
-     * Returns the value of this {@code AtomicInteger} as an {@code int}.
+     * Returns the current value of this {@code AtomicInteger} as an
+     * {@code int},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
      * Equivalent to {@link #get()}.
      */
     public int intValue() {
@@ -309,8 +340,9 @@
     }
 
     /**
-     * Returns the value of this {@code AtomicInteger} as a {@code long}
-     * after a widening primitive conversion.
+     * Returns the current value of this {@code AtomicInteger} as a
+     * {@code long} after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      * @jls 5.1.2 Widening Primitive Conversions
      */
     public long longValue() {
@@ -318,8 +350,9 @@
     }
 
     /**
-     * Returns the value of this {@code AtomicInteger} as a {@code float}
-     * after a widening primitive conversion.
+     * Returns the current value of this {@code AtomicInteger} as a
+     * {@code float} after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      * @jls 5.1.2 Widening Primitive Conversions
      */
     public float floatValue() {
@@ -327,12 +360,175 @@
     }
 
     /**
-     * Returns the value of this {@code AtomicInteger} as a {@code double}
-     * after a widening primitive conversion.
+     * Returns the current value of this {@code AtomicInteger} as a
+     * {@code double} after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      * @jls 5.1.2 Widening Primitive Conversions
      */
     public double doubleValue() {
         return (double)get();
     }
 
+    // jdk9
+
+    /**
+     * Returns the current value, with memory semantics of reading as
+     * if the variable was declared non-{@code volatile}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final int getPlain() {
+        return U.getInt(this, VALUE);
+    }
+
+    /**
+     * Sets the value to {@code newValue}, with memory semantics
+     * of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(int newValue) {
+        U.putInt(this, VALUE, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final int getOpaque() {
+        return U.getIntOpaque(this, VALUE);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(int newValue) {
+        U.putIntOpaque(this, VALUE, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final int getAcquire() {
+        return U.getIntAcquire(this, VALUE);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(int newValue) {
+        U.putIntRelease(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchange(int expectedValue, int newValue) {
+        return U.compareAndExchangeIntVolatile(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchangeAcquire(int expectedValue, int newValue) {
+        return U.compareAndExchangeIntAcquire(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchangeRelease(int expectedValue, int newValue) {
+        return U.compareAndExchangeIntRelease(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if
+     * the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetVolatile}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(int expectedValue, int newValue) {
+        return U.weakCompareAndSwapIntVolatile(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if
+     * the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(int expectedValue, int newValue) {
+        return U.weakCompareAndSwapIntAcquire(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if
+     * the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(int expectedValue, int newValue) {
+        return U.weakCompareAndSwapIntRelease(this, VALUE, expectedValue, newValue);
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,44 +35,24 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntUnaryOperator;
 
 /**
  * An {@code int} array in which elements may be updated atomically.
- * See the {@link java.util.concurrent.atomic} package
- * specification for description of the properties of atomic
- * variables.
+ * See the {@link VarHandle} specification for descriptions of the
+ * properties of atomic accesses.
  * @since 1.5
  * @author Doug Lea
  */
 public class AtomicIntegerArray implements java.io.Serializable {
     private static final long serialVersionUID = 2862133569453604235L;
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final int ABASE;
-    private static final int ASHIFT;
+    private static final VarHandle AA
+        = MethodHandles.arrayElementVarHandle(int[].class);
     private final int[] array;
 
-    static {
-        ABASE = U.arrayBaseOffset(int[].class);
-        int scale = U.arrayIndexScale(int[].class);
-        if ((scale & (scale - 1)) != 0)
-            throw new Error("array index scale not a power of two");
-        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
-    }
-
-    private long checkedByteOffset(int i) {
-        if (i < 0 || i >= array.length)
-            throw new IndexOutOfBoundsException("index " + i);
-
-        return byteOffset(i);
-    }
-
-    private static long byteOffset(int i) {
-        return ((long) i << ASHIFT) + ABASE;
-    }
-
     /**
      * Creates a new AtomicIntegerArray of the given length, with all
      * elements initially zero.
@@ -105,147 +85,155 @@
     }
 
     /**
-     * Gets the current value at position {@code i}.
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      *
      * @param i the index
      * @return the current value
      */
     public final int get(int i) {
-        return getRaw(checkedByteOffset(i));
-    }
-
-    private int getRaw(long offset) {
-        return U.getIntVolatile(array, offset);
+        return (int)AA.getVolatile(array, i);
     }
 
     /**
-     * Sets the element at position {@code i} to the given value.
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
      *
      * @param i the index
      * @param newValue the new value
      */
     public final void set(int i, int newValue) {
-        U.putIntVolatile(array, checkedByteOffset(i), newValue);
+        AA.setVolatile(array, i, newValue);
     }
 
     /**
-     * Eventually sets the element at position {@code i} to the given value.
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
      *
      * @param i the index
      * @param newValue the new value
      * @since 1.6
      */
     public final void lazySet(int i, int newValue) {
-        U.putIntRelease(array, checkedByteOffset(i), newValue);
+        AA.setRelease(array, i, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given
-     * value and returns the old value.
+     * Atomically sets the element at index {@code i} to {@code
+     * newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
      *
      * @param i the index
      * @param newValue the new value
      * @return the previous value
      */
     public final int getAndSet(int i, int newValue) {
-        return U.getAndSetInt(array, checkedByteOffset(i), newValue);
+        return (int)AA.getAndSet(array, i, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given
-     * updated value if the current value {@code ==} the expected value.
+     * Atomically sets the element at index {@code i} to {@code
+     * newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
      *
      * @param i the index
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful. False return indicates that
      * the actual value was not equal to the expected value.
      */
-    public final boolean compareAndSet(int i, int expect, int update) {
-        return compareAndSetRaw(checkedByteOffset(i), expect, update);
-    }
-
-    private boolean compareAndSetRaw(long offset, int expect, int update) {
-        return U.compareAndSwapInt(array, offset, expect, update);
+    public final boolean compareAndSet(int i, int expectedValue, int newValue) {
+        return AA.compareAndSet(array, i, expectedValue, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given
-     * updated value if the current value {@code ==} the expected value.
-     *
-     * <p><a href="package-summary.html#weakCompareAndSet">May fail
-     * spuriously and does not provide ordering guarantees</a>, so is
-     * only rarely an appropriate alternative to {@code compareAndSet}.
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
      *
      * @param i the index
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful
      */
-    public final boolean weakCompareAndSet(int i, int expect, int update) {
-        return compareAndSet(i, expect, update);
+    public final boolean weakCompareAndSet(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSet(array, i, expectedValue, newValue);
     }
 
     /**
-     * Atomically increments by one the element at index {@code i}.
+     * Atomically increments the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(i, 1)}.
      *
      * @param i the index
      * @return the previous value
      */
     public final int getAndIncrement(int i) {
-        return getAndAdd(i, 1);
+        return (int)AA.getAndAdd(array, i, 1);
     }
 
     /**
-     * Atomically decrements by one the element at index {@code i}.
+     * Atomically decrements the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(i, -1)}.
      *
      * @param i the index
      * @return the previous value
      */
     public final int getAndDecrement(int i) {
-        return getAndAdd(i, -1);
+        return (int)AA.getAndAdd(array, i, -1);
     }
 
     /**
-     * Atomically adds the given value to the element at index {@code i}.
+     * Atomically adds the given value to the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
      *
      * @param i the index
      * @param delta the value to add
      * @return the previous value
      */
     public final int getAndAdd(int i, int delta) {
-        return U.getAndAddInt(array, checkedByteOffset(i), delta);
+        return (int)AA.getAndAdd(array, i, delta);
     }
 
     /**
-     * Atomically increments by one the element at index {@code i}.
+     * Atomically increments the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
+     *
+     * <p>Equivalent to {@code addAndGet(i, 1)}.
      *
      * @param i the index
      * @return the updated value
      */
     public final int incrementAndGet(int i) {
-        return getAndAdd(i, 1) + 1;
+        return (int)AA.addAndGet(array, i, 1);
     }
 
     /**
-     * Atomically decrements by one the element at index {@code i}.
+     * Atomically decrements the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
+     *
+     * <p>Equivalent to {@code addAndGet(i, -1)}.
      *
      * @param i the index
      * @return the updated value
      */
     public final int decrementAndGet(int i) {
-        return getAndAdd(i, -1) - 1;
+        return (int)AA.addAndGet(array, i, -1);
     }
 
     /**
-     * Atomically adds the given value to the element at index {@code i}.
+     * Atomically adds the given value to the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
      *
      * @param i the index
      * @param delta the value to add
      * @return the updated value
      */
     public final int addAndGet(int i, int delta) {
-        return getAndAdd(i, delta) + delta;
+        return (int)AA.addAndGet(array, i, delta);
     }
 
     /**
@@ -260,13 +248,14 @@
      * @since 1.8
      */
     public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
-        long offset = checkedByteOffset(i);
-        int prev, next;
-        do {
-            prev = getRaw(offset);
-            next = updateFunction.applyAsInt(prev);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return prev;
+        int prev = get(i), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsInt(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
@@ -281,23 +270,25 @@
      * @since 1.8
      */
     public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
-        long offset = checkedByteOffset(i);
-        int prev, next;
-        do {
-            prev = getRaw(offset);
-            next = updateFunction.applyAsInt(prev);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return next;
+        int prev = get(i), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsInt(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
      * Atomically updates the element at index {@code i} with the
-     * results of applying the given function to the current and
-     * given values, returning the previous value. The function should
-     * be side-effect-free, since it may be re-applied when attempted
+     * results of applying the given function to the current and given
+     * values, returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
      * updates fail due to contention among threads.  The function is
-     * applied with the current value at index {@code i} as its first
-     * argument, and the given update as the second argument.
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
      *
      * @param i the index
      * @param x the update value
@@ -307,23 +298,25 @@
      */
     public final int getAndAccumulate(int i, int x,
                                       IntBinaryOperator accumulatorFunction) {
-        long offset = checkedByteOffset(i);
-        int prev, next;
-        do {
-            prev = getRaw(offset);
-            next = accumulatorFunction.applyAsInt(prev, x);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return prev;
+        int prev = get(i), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsInt(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
      * Atomically updates the element at index {@code i} with the
-     * results of applying the given function to the current and
-     * given values, returning the updated value. The function should
-     * be side-effect-free, since it may be re-applied when attempted
+     * results of applying the given function to the current and given
+     * values, returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
      * updates fail due to contention among threads.  The function is
-     * applied with the current value at index {@code i} as its first
-     * argument, and the given update as the second argument.
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
      *
      * @param i the index
      * @param x the update value
@@ -333,13 +326,14 @@
      */
     public final int accumulateAndGet(int i, int x,
                                       IntBinaryOperator accumulatorFunction) {
-        long offset = checkedByteOffset(i);
-        int prev, next;
-        do {
-            prev = getRaw(offset);
-            next = accumulatorFunction.applyAsInt(prev, x);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return next;
+        int prev = get(i), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsInt(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
@@ -354,11 +348,190 @@
         StringBuilder b = new StringBuilder();
         b.append('[');
         for (int i = 0; ; i++) {
-            b.append(getRaw(byteOffset(i)));
+            b.append(get(i));
             if (i == iMax)
                 return b.append(']').toString();
             b.append(',').append(' ');
         }
     }
 
+    // jdk9
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory semantics of reading as if the variable was declared
+     * non-{@code volatile}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final int getPlain(int i) {
+        return (int)AA.get(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory semantics of setting as if the variable was
+     * declared non-{@code volatile} and non-{@code final}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(int i, int newValue) {
+        AA.set(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final int getOpaque(int i) {
+        return (int)AA.getOpaque(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(int i, int newValue) {
+        AA.setOpaque(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final int getAcquire(int i) {
+        return (int)AA.getAcquire(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(int i, int newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchange(int i, int expectedValue, int newValue) {
+        return (int)AA.compareAndExchange(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchangeAcquire(int i, int expectedValue, int newValue) {
+        return (int)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchangeRelease(int i, int expectedValue, int newValue) {
+        return (int)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetVolatile}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
+    }
+
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Wed Jul 05 22:00:06 2017 +0200
@@ -42,6 +42,7 @@
 import java.security.PrivilegedExceptionAction;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntUnaryOperator;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 
@@ -150,8 +151,8 @@
     public abstract void lazySet(T obj, int newValue);
 
     /**
-     * Gets the current value held in the field of the given object managed
-     * by this updater.
+     * Returns the current value held in the field of the given object
+     * managed by this updater.
      *
      * @param obj An object whose field to get
      * @return the current value
@@ -367,7 +368,7 @@
      */
     private static final class AtomicIntegerFieldUpdaterImpl<T>
         extends AtomicIntegerFieldUpdater<T> {
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+        private static final Unsafe U = Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,18 +35,18 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.VarHandle;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
 
 /**
  * A {@code long} value that may be updated atomically.  See the
- * {@link java.util.concurrent.atomic} package specification for
- * description of the properties of atomic variables. An
- * {@code AtomicLong} is used in applications such as atomically
- * incremented sequence numbers, and cannot be used as a replacement
- * for a {@link java.lang.Long}. However, this class does extend
- * {@code Number} to allow uniform access by tools and utilities that
- * deal with numerically-based classes.
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicLong} is used in applications
+ * such as atomically incremented sequence numbers, and cannot be used
+ * as a replacement for a {@link java.lang.Long}. However, this class
+ * does extend {@code Number} to allow uniform access by tools and
+ * utilities that deal with numerically-based classes.
  *
  * @since 1.5
  * @author Doug Lea
@@ -54,12 +54,9 @@
 public class AtomicLong extends Number implements java.io.Serializable {
     private static final long serialVersionUID = 1927816293512124184L;
 
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long VALUE;
-
     /**
      * Records whether the underlying JVM supports lockless
-     * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
+     * compareAndSwap for longs. While the intrinsic compareAndSwapLong
      * method works in either case, some constructions should be
      * handled at Java level to avoid locking user-visible locks.
      */
@@ -71,6 +68,13 @@
      */
     private static native boolean VMSupportsCS8();
 
+    /*
+     * This class intended to be implemented using VarHandles, but there
+     * are unresolved cyclic startup dependencies.
+     */
+    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
     static {
         try {
             VALUE = U.objectFieldOffset
@@ -98,7 +102,8 @@
     }
 
     /**
-     * Gets the current value.
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      *
      * @return the current value
      */
@@ -107,7 +112,8 @@
     }
 
     /**
-     * Sets to the given value.
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
      *
      * @param newValue the new value
      */
@@ -118,7 +124,8 @@
     }
 
     /**
-     * Eventually sets to the given value.
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
      *
      * @param newValue the new value
      * @since 1.6
@@ -128,7 +135,8 @@
     }
 
     /**
-     * Atomically sets to the given value and returns the old value.
+     * Atomically sets the value to {@code newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
      *
      * @param newValue the new value
      * @return the previous value
@@ -138,36 +146,37 @@
     }
 
     /**
-     * Atomically sets the value to the given updated value
-     * if the current value {@code ==} the expected value.
+     * Atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
      *
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful. False return indicates that
      * the actual value was not equal to the expected value.
      */
-    public final boolean compareAndSet(long expect, long update) {
-        return U.compareAndSwapLong(this, VALUE, expect, update);
+    public final boolean compareAndSet(long expectedValue, long newValue) {
+        return U.compareAndSwapLong(this, VALUE, expectedValue, newValue);
     }
 
     /**
-     * Atomically sets the value to the given updated value
-     * if the current value {@code ==} the expected value.
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
      *
-     * <p><a href="package-summary.html#weakCompareAndSet">May fail
-     * spuriously and does not provide ordering guarantees</a>, so is
-     * only rarely an appropriate alternative to {@code compareAndSet}.
-     *
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful
      */
-    public final boolean weakCompareAndSet(long expect, long update) {
-        return U.compareAndSwapLong(this, VALUE, expect, update);
+    public final boolean weakCompareAndSet(long expectedValue, long newValue) {
+        return U.weakCompareAndSwapLong(this, VALUE, expectedValue, newValue);
     }
 
     /**
-     * Atomically increments by one the current value.
+     * Atomically increments the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(1)}.
      *
      * @return the previous value
      */
@@ -176,7 +185,10 @@
     }
 
     /**
-     * Atomically decrements by one the current value.
+     * Atomically decrements the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(-1)}.
      *
      * @return the previous value
      */
@@ -185,7 +197,8 @@
     }
 
     /**
-     * Atomically adds the given value to the current value.
+     * Atomically adds the given value to the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
      *
      * @param delta the value to add
      * @return the previous value
@@ -195,7 +208,10 @@
     }
 
     /**
-     * Atomically increments by one the current value.
+     * Atomically increments the current value,
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
+     *
+     * <p>Equivalent to {@code addAndGet(1)}.
      *
      * @return the updated value
      */
@@ -204,7 +220,10 @@
     }
 
     /**
-     * Atomically decrements by one the current value.
+     * Atomically decrements the current value,
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
+     *
+     * <p>Equivalent to {@code addAndGet(-1)}.
      *
      * @return the updated value
      */
@@ -213,7 +232,8 @@
     }
 
     /**
-     * Atomically adds the given value to the current value.
+     * Atomically adds the given value to the current value,
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
      *
      * @param delta the value to add
      * @return the updated value
@@ -233,12 +253,14 @@
      * @since 1.8
      */
     public final long getAndUpdate(LongUnaryOperator updateFunction) {
-        long prev, next;
-        do {
-            prev = get();
-            next = updateFunction.applyAsLong(prev);
-        } while (!compareAndSet(prev, next));
-        return prev;
+        long prev = get(), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsLong(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -252,12 +274,14 @@
      * @since 1.8
      */
     public final long updateAndGet(LongUnaryOperator updateFunction) {
-        long prev, next;
-        do {
-            prev = get();
-            next = updateFunction.applyAsLong(prev);
-        } while (!compareAndSet(prev, next));
-        return next;
+        long prev = get(), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsLong(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -276,12 +300,14 @@
      */
     public final long getAndAccumulate(long x,
                                        LongBinaryOperator accumulatorFunction) {
-        long prev, next;
-        do {
-            prev = get();
-            next = accumulatorFunction.applyAsLong(prev, x);
-        } while (!compareAndSet(prev, next));
-        return prev;
+        long prev = get(), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsLong(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -300,12 +326,14 @@
      */
     public final long accumulateAndGet(long x,
                                        LongBinaryOperator accumulatorFunction) {
-        long prev, next;
-        do {
-            prev = get();
-            next = accumulatorFunction.applyAsLong(prev, x);
-        } while (!compareAndSet(prev, next));
-        return next;
+        long prev = get(), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsLong(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -317,8 +345,9 @@
     }
 
     /**
-     * Returns the value of this {@code AtomicLong} as an {@code int}
-     * after a narrowing primitive conversion.
+     * Returns the current value of this {@code AtomicLong} as an {@code int}
+     * after a narrowing primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      * @jls 5.1.3 Narrowing Primitive Conversions
      */
     public int intValue() {
@@ -326,7 +355,8 @@
     }
 
     /**
-     * Returns the value of this {@code AtomicLong} as a {@code long}.
+     * Returns the current value of this {@code AtomicLong} as a {@code long},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      * Equivalent to {@link #get()}.
      */
     public long longValue() {
@@ -334,8 +364,9 @@
     }
 
     /**
-     * Returns the value of this {@code AtomicLong} as a {@code float}
-     * after a widening primitive conversion.
+     * Returns the current value of this {@code AtomicLong} as a {@code float}
+     * after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      * @jls 5.1.2 Widening Primitive Conversions
      */
     public float floatValue() {
@@ -343,12 +374,175 @@
     }
 
     /**
-     * Returns the value of this {@code AtomicLong} as a {@code double}
-     * after a widening primitive conversion.
+     * Returns the current value of this {@code AtomicLong} as a {@code double}
+     * after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      * @jls 5.1.2 Widening Primitive Conversions
      */
     public double doubleValue() {
         return (double)get();
     }
 
+    // jdk9
+
+    /**
+     * Returns the current value, with memory semantics of reading as if the
+     * variable was declared non-{@code volatile}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final long getPlain() {
+        return U.getLong(this, VALUE);
+    }
+
+    /**
+     * Sets the value to {@code newValue}, with memory semantics
+     * of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(long newValue) {
+        U.putLong(this, VALUE, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final long getOpaque() {
+        return U.getLongOpaque(this, VALUE);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(long newValue) {
+        U.putLongOpaque(this, VALUE, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final long getAcquire() {
+        return U.getLongAcquire(this, VALUE);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(long newValue) {
+        U.putLongRelease(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchange(long expectedValue, long newValue) {
+        return U.compareAndExchangeLongVolatile(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchangeAcquire(long expectedValue, long newValue) {
+        return U.compareAndExchangeLongAcquire(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchangeRelease(long expectedValue, long newValue) {
+        return U.compareAndExchangeLongRelease(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetVolatile}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(long expectedValue, long newValue) {
+        return U.weakCompareAndSwapLongVolatile(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(long expectedValue, long newValue) {
+        return U.weakCompareAndSwapLongAcquire(this, VALUE, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(long expectedValue, long newValue) {
+        return U.weakCompareAndSwapLongRelease(this, VALUE, expectedValue, newValue);
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongArray.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongArray.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,43 +35,24 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
 
 /**
  * A {@code long} array in which elements may be updated atomically.
- * See the {@link java.util.concurrent.atomic} package specification
- * for description of the properties of atomic variables.
+ * See the {@link VarHandle} specification for descriptions of the
+ * properties of atomic accesses.
  * @since 1.5
  * @author Doug Lea
  */
 public class AtomicLongArray implements java.io.Serializable {
     private static final long serialVersionUID = -2308431214976778248L;
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final int ABASE;
-    private static final int ASHIFT;
+    private static final VarHandle AA
+        = MethodHandles.arrayElementVarHandle(long[].class);
     private final long[] array;
 
-    static {
-        ABASE = U.arrayBaseOffset(long[].class);
-        int scale = U.arrayIndexScale(long[].class);
-        if ((scale & (scale - 1)) != 0)
-            throw new Error("array index scale not a power of two");
-        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
-    }
-
-    private long checkedByteOffset(int i) {
-        if (i < 0 || i >= array.length)
-            throw new IndexOutOfBoundsException("index " + i);
-
-        return byteOffset(i);
-    }
-
-    private static long byteOffset(int i) {
-        return ((long) i << ASHIFT) + ABASE;
-    }
-
     /**
      * Creates a new AtomicLongArray of the given length, with all
      * elements initially zero.
@@ -104,147 +85,155 @@
     }
 
     /**
-     * Gets the current value at position {@code i}.
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      *
      * @param i the index
      * @return the current value
      */
     public final long get(int i) {
-        return getRaw(checkedByteOffset(i));
-    }
-
-    private long getRaw(long offset) {
-        return U.getLongVolatile(array, offset);
+        return (long)AA.getVolatile(array, i);
     }
 
     /**
-     * Sets the element at position {@code i} to the given value.
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
      *
      * @param i the index
      * @param newValue the new value
      */
     public final void set(int i, long newValue) {
-        U.putLongVolatile(array, checkedByteOffset(i), newValue);
+        AA.setVolatile(array, i, newValue);
     }
 
     /**
-     * Eventually sets the element at position {@code i} to the given value.
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
      *
      * @param i the index
      * @param newValue the new value
      * @since 1.6
      */
     public final void lazySet(int i, long newValue) {
-        U.putLongRelease(array, checkedByteOffset(i), newValue);
+        AA.setRelease(array, i, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given value
-     * and returns the old value.
+     * Atomically sets the element at index {@code i} to {@code
+     * newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
      *
      * @param i the index
      * @param newValue the new value
      * @return the previous value
      */
     public final long getAndSet(int i, long newValue) {
-        return U.getAndSetLong(array, checkedByteOffset(i), newValue);
+        return (long)AA.getAndSet(array, i, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given
-     * updated value if the current value {@code ==} the expected value.
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
      *
      * @param i the index
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful. False return indicates that
      * the actual value was not equal to the expected value.
      */
-    public final boolean compareAndSet(int i, long expect, long update) {
-        return compareAndSetRaw(checkedByteOffset(i), expect, update);
-    }
-
-    private boolean compareAndSetRaw(long offset, long expect, long update) {
-        return U.compareAndSwapLong(array, offset, expect, update);
+    public final boolean compareAndSet(int i, long expectedValue, long newValue) {
+        return AA.compareAndSet(array, i, expectedValue, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given
-     * updated value if the current value {@code ==} the expected value.
-     *
-     * <p><a href="package-summary.html#weakCompareAndSet">May fail
-     * spuriously and does not provide ordering guarantees</a>, so is
-     * only rarely an appropriate alternative to {@code compareAndSet}.
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
      *
      * @param i the index
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful
      */
-    public final boolean weakCompareAndSet(int i, long expect, long update) {
-        return compareAndSet(i, expect, update);
+    public final boolean weakCompareAndSet(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSet(array, i, expectedValue, newValue);
     }
 
     /**
-     * Atomically increments by one the element at index {@code i}.
+     * Atomically increments the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(i, 1)}.
      *
      * @param i the index
      * @return the previous value
      */
     public final long getAndIncrement(int i) {
-        return getAndAdd(i, 1);
+        return (long)AA.getAndAdd(array, i, 1L);
     }
 
     /**
-     * Atomically decrements by one the element at index {@code i}.
+     * Atomically decrements the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(i, -1)}.
      *
      * @param i the index
      * @return the previous value
      */
     public final long getAndDecrement(int i) {
-        return getAndAdd(i, -1);
+        return (long)AA.getAndAdd(array, i, -1L);
     }
 
     /**
-     * Atomically adds the given value to the element at index {@code i}.
+     * Atomically adds the given value to the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
      *
      * @param i the index
      * @param delta the value to add
      * @return the previous value
      */
     public final long getAndAdd(int i, long delta) {
-        return U.getAndAddLong(array, checkedByteOffset(i), delta);
+        return (long)AA.getAndAdd(array, i, delta);
     }
 
     /**
-     * Atomically increments by one the element at index {@code i}.
+     * Atomically increments the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
+     *
+     * <p>Equivalent to {@code addAndGet(i, 1)}.
      *
      * @param i the index
      * @return the updated value
      */
     public final long incrementAndGet(int i) {
-        return getAndAdd(i, 1) + 1;
+        return (long)AA.addAndGet(array, i, 1L);
     }
 
     /**
-     * Atomically decrements by one the element at index {@code i}.
+     * Atomically decrements the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
+     *
+     * <p>Equivalent to {@code addAndGet(i, -1)}.
      *
      * @param i the index
      * @return the updated value
      */
     public final long decrementAndGet(int i) {
-        return getAndAdd(i, -1) - 1;
+        return (long)AA.addAndGet(array, i, -1L);
     }
 
     /**
-     * Atomically adds the given value to the element at index {@code i}.
+     * Atomically adds the given value to the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#addAndGet}.
      *
      * @param i the index
      * @param delta the value to add
      * @return the updated value
      */
     public long addAndGet(int i, long delta) {
-        return getAndAdd(i, delta) + delta;
+        return (long)AA.addAndGet(array, i, delta);
     }
 
     /**
@@ -259,13 +248,14 @@
      * @since 1.8
      */
     public final long getAndUpdate(int i, LongUnaryOperator updateFunction) {
-        long offset = checkedByteOffset(i);
-        long prev, next;
-        do {
-            prev = getRaw(offset);
-            next = updateFunction.applyAsLong(prev);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return prev;
+        long prev = get(i), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsLong(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
@@ -280,23 +270,25 @@
      * @since 1.8
      */
     public final long updateAndGet(int i, LongUnaryOperator updateFunction) {
-        long offset = checkedByteOffset(i);
-        long prev, next;
-        do {
-            prev = getRaw(offset);
-            next = updateFunction.applyAsLong(prev);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return next;
+        long prev = get(i), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsLong(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
      * Atomically updates the element at index {@code i} with the
-     * results of applying the given function to the current and
-     * given values, returning the previous value. The function should
-     * be side-effect-free, since it may be re-applied when attempted
+     * results of applying the given function to the current and given
+     * values, returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
      * updates fail due to contention among threads.  The function is
-     * applied with the current value at index {@code i} as its first
-     * argument, and the given update as the second argument.
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
      *
      * @param i the index
      * @param x the update value
@@ -306,23 +298,25 @@
      */
     public final long getAndAccumulate(int i, long x,
                                       LongBinaryOperator accumulatorFunction) {
-        long offset = checkedByteOffset(i);
-        long prev, next;
-        do {
-            prev = getRaw(offset);
-            next = accumulatorFunction.applyAsLong(prev, x);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return prev;
+        long prev = get(i), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsLong(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
      * Atomically updates the element at index {@code i} with the
-     * results of applying the given function to the current and
-     * given values, returning the updated value. The function should
-     * be side-effect-free, since it may be re-applied when attempted
+     * results of applying the given function to the current and given
+     * values, returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
      * updates fail due to contention among threads.  The function is
-     * applied with the current value at index {@code i} as its first
-     * argument, and the given update as the second argument.
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
      *
      * @param i the index
      * @param x the update value
@@ -332,13 +326,14 @@
      */
     public final long accumulateAndGet(int i, long x,
                                       LongBinaryOperator accumulatorFunction) {
-        long offset = checkedByteOffset(i);
-        long prev, next;
-        do {
-            prev = getRaw(offset);
-            next = accumulatorFunction.applyAsLong(prev, x);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return next;
+        long prev = get(i), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsLong(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
@@ -353,11 +348,189 @@
         StringBuilder b = new StringBuilder();
         b.append('[');
         for (int i = 0; ; i++) {
-            b.append(getRaw(byteOffset(i)));
+            b.append(get(i));
             if (i == iMax)
                 return b.append(']').toString();
             b.append(',').append(' ');
         }
     }
 
+    // jdk9
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory semantics of reading as if the variable was declared
+     * non-{@code volatile}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final long getPlain(int i) {
+        return (long)AA.get(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory semantics of setting as if the variable was
+     * declared non-{@code volatile} and non-{@code final}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(int i, long newValue) {
+        AA.set(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final long getOpaque(int i) {
+        return (long)AA.getOpaque(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(int i, long newValue) {
+        AA.setOpaque(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final long getAcquire(int i) {
+        return (long)AA.getAcquire(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(int i, long newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchange(int i, long expectedValue, long newValue) {
+        return (long)AA.compareAndExchange(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchangeAcquire(int i, long expectedValue, long newValue) {
+        return (long)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchangeRelease(int i, long expectedValue, long newValue) {
+        return (long)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetVolatile}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Wed Jul 05 22:00:06 2017 +0200
@@ -42,6 +42,7 @@
 import java.security.PrivilegedExceptionAction;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 
@@ -153,8 +154,8 @@
     public abstract void lazySet(T obj, long newValue);
 
     /**
-     * Gets the current value held in the field of the given object managed
-     * by this updater.
+     * Returns the current value held in the field of the given object
+     * managed by this updater.
      *
      * @param obj An object whose field to get
      * @return the current value
@@ -366,7 +367,7 @@
     }
 
     private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+        private static final Unsafe U = Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
@@ -497,7 +498,7 @@
     }
 
     private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+        private static final Unsafe U = Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,9 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
 /**
  * An {@code AtomicMarkableReference} maintains an object reference
  * along with a mark bit, that can be updated atomically.
@@ -188,20 +191,19 @@
              casPair(current, Pair.of(expectedReference, newMark)));
     }
 
-    // Unsafe mechanics
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long PAIR;
+    // VarHandle mechanics
+    private static final VarHandle PAIR;
     static {
         try {
-            PAIR = U.objectFieldOffset
-                (AtomicMarkableReference.class.getDeclaredField("pair"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
+                                   Pair.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
     }
 
     private boolean casPair(Pair<V> cmp, Pair<V> val) {
-        return U.compareAndSwapObject(this, PAIR, cmp, val);
+        return PAIR.compareAndSet(this, cmp, val);
     }
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,27 +35,26 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.function.BinaryOperator;
 import java.util.function.UnaryOperator;
 
 /**
- * An object reference that may be updated atomically. See the {@link
- * java.util.concurrent.atomic} package specification for description
- * of the properties of atomic variables.
+ * An object reference that may be updated atomically.  See the {@link
+ * VarHandle} specification for descriptions of the properties of
+ * atomic accesses.
  * @since 1.5
  * @author Doug Lea
  * @param <V> The type of object referred to by this reference
  */
 public class AtomicReference<V> implements java.io.Serializable {
     private static final long serialVersionUID = -1848883965231344442L;
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long VALUE;
-
+    private static final VarHandle VALUE;
     static {
         try {
-            VALUE = U.objectFieldOffset
-                (AtomicReference.class.getDeclaredField("value"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
@@ -79,7 +78,8 @@
     }
 
     /**
-     * Gets the current value.
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      *
      * @return the current value
      */
@@ -88,7 +88,8 @@
     }
 
     /**
-     * Sets to the given value.
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
      *
      * @param newValue the new value
      */
@@ -97,52 +98,53 @@
     }
 
     /**
-     * Eventually sets to the given value.
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
      *
      * @param newValue the new value
      * @since 1.6
      */
     public final void lazySet(V newValue) {
-        U.putObjectRelease(this, VALUE, newValue);
-    }
-
-    /**
-     * Atomically sets the value to the given updated value
-     * if the current value {@code ==} the expected value.
-     * @param expect the expected value
-     * @param update the new value
-     * @return {@code true} if successful. False return indicates that
-     * the actual value was not equal to the expected value.
-     */
-    public final boolean compareAndSet(V expect, V update) {
-        return U.compareAndSwapObject(this, VALUE, expect, update);
+        VALUE.setRelease(this, newValue);
     }
 
     /**
-     * Atomically sets the value to the given updated value
-     * if the current value {@code ==} the expected value.
-     *
-     * <p><a href="package-summary.html#weakCompareAndSet">May fail
-     * spuriously and does not provide ordering guarantees</a>, so is
-     * only rarely an appropriate alternative to {@code compareAndSet}.
+     * Atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
      *
-     * @param expect the expected value
-     * @param update the new value
-     * @return {@code true} if successful
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
      */
-    public final boolean weakCompareAndSet(V expect, V update) {
-        return U.compareAndSwapObject(this, VALUE, expect, update);
+    public final boolean compareAndSet(V expectedValue, V newValue) {
+        return VALUE.compareAndSet(this, expectedValue, newValue);
     }
 
     /**
-     * Atomically sets to the given value and returns the old value.
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
      *
      * @param newValue the new value
      * @return the previous value
      */
     @SuppressWarnings("unchecked")
     public final V getAndSet(V newValue) {
-        return (V)U.getAndSetObject(this, VALUE, newValue);
+        return (V)VALUE.getAndSet(this, newValue);
     }
 
     /**
@@ -156,12 +158,14 @@
      * @since 1.8
      */
     public final V getAndUpdate(UnaryOperator<V> updateFunction) {
-        V prev, next;
-        do {
-            prev = get();
-            next = updateFunction.apply(prev);
-        } while (!compareAndSet(prev, next));
-        return prev;
+        V prev = get(), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.apply(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -175,12 +179,14 @@
      * @since 1.8
      */
     public final V updateAndGet(UnaryOperator<V> updateFunction) {
-        V prev, next;
-        do {
-            prev = get();
-            next = updateFunction.apply(prev);
-        } while (!compareAndSet(prev, next));
-        return next;
+        V prev = get(), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.apply(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -199,12 +205,14 @@
      */
     public final V getAndAccumulate(V x,
                                     BinaryOperator<V> accumulatorFunction) {
-        V prev, next;
-        do {
-            prev = get();
-            next = accumulatorFunction.apply(prev, x);
-        } while (!compareAndSet(prev, next));
-        return prev;
+        V prev = get(), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.apply(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -223,12 +231,14 @@
      */
     public final V accumulateAndGet(V x,
                                     BinaryOperator<V> accumulatorFunction) {
-        V prev, next;
-        do {
-            prev = get();
-            next = accumulatorFunction.apply(prev, x);
-        } while (!compareAndSet(prev, next));
-        return next;
+        V prev = get(), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.apply(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
     }
 
     /**
@@ -239,4 +249,166 @@
         return String.valueOf(get());
     }
 
+    // jdk9
+
+    /**
+     * Returns the current value, with memory semantics of reading as
+     * if the variable was declared non-{@code volatile}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final V getPlain() {
+        return (V)VALUE.get(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue}, with memory semantics
+     * of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(V newValue) {
+        VALUE.set(this, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final V getOpaque() {
+        return (V)VALUE.getOpaque(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(V newValue) {
+        VALUE.setOpaque(this, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final V getAcquire() {
+        return (V)VALUE.getAcquire(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(V newValue) {
+        VALUE.setRelease(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final V compareAndExchange(V expectedValue, V newValue) {
+        return (V)VALUE.compareAndExchange(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final V compareAndExchangeAcquire(V expectedValue, V newValue) {
+        return (V)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final V compareAndExchangeRelease(V expectedValue, V newValue) {
+        return (V)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetVolatile}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,54 +35,28 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.lang.reflect.Array;
+import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.function.BinaryOperator;
 import java.util.function.UnaryOperator;
 
 /**
  * An array of object references in which elements may be updated
- * atomically.  See the {@link java.util.concurrent.atomic} package
- * specification for description of the properties of atomic
- * variables.
+ * atomically.  See the {@link VarHandle} specification for
+ * descriptions of the properties of atomic accesses.
  * @since 1.5
  * @author Doug Lea
  * @param <E> The base class of elements held in this array
  */
 public class AtomicReferenceArray<E> implements java.io.Serializable {
     private static final long serialVersionUID = -6209656149925076980L;
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long ARRAY;
-    private static final int ABASE;
-    private static final int ASHIFT;
+    private static final VarHandle AA
+        = MethodHandles.arrayElementVarHandle(Object[].class);
     private final Object[] array; // must have exact type Object[]
 
-    static {
-        try {
-            ARRAY = U.objectFieldOffset
-                (AtomicReferenceArray.class.getDeclaredField("array"));
-            ABASE = U.arrayBaseOffset(Object[].class);
-            int scale = U.arrayIndexScale(Object[].class);
-            if ((scale & (scale - 1)) != 0)
-                throw new Error("array index scale not a power of two");
-            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
-        } catch (ReflectiveOperationException e) {
-            throw new Error(e);
-        }
-    }
-
-    private long checkedByteOffset(int i) {
-        if (i < 0 || i >= array.length)
-            throw new IndexOutOfBoundsException("index " + i);
-
-        return byteOffset(i);
-    }
-
-    private static long byteOffset(int i) {
-        return ((long) i << ASHIFT) + ABASE;
-    }
-
     /**
      * Creates a new AtomicReferenceArray of the given length, with all
      * elements initially null.
@@ -115,44 +89,44 @@
     }
 
     /**
-     * Gets the current value at position {@code i}.
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
      *
      * @param i the index
      * @return the current value
      */
+    @SuppressWarnings("unchecked")
     public final E get(int i) {
-        return getRaw(checkedByteOffset(i));
-    }
-
-    @SuppressWarnings("unchecked")
-    private E getRaw(long offset) {
-        return (E) U.getObjectVolatile(array, offset);
+        return (E)AA.getVolatile(array, i);
     }
 
     /**
-     * Sets the element at position {@code i} to the given value.
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
      *
      * @param i the index
      * @param newValue the new value
      */
     public final void set(int i, E newValue) {
-        U.putObjectVolatile(array, checkedByteOffset(i), newValue);
+        AA.setVolatile(array, i, newValue);
     }
 
     /**
-     * Eventually sets the element at position {@code i} to the given value.
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
      *
      * @param i the index
      * @param newValue the new value
      * @since 1.6
      */
     public final void lazySet(int i, E newValue) {
-        U.putObjectRelease(array, checkedByteOffset(i), newValue);
+        AA.setRelease(array, i, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given
-     * value and returns the old value.
+     * Atomically sets the element at index {@code i} to {@code
+     * newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
      *
      * @param i the index
      * @param newValue the new value
@@ -160,42 +134,36 @@
      */
     @SuppressWarnings("unchecked")
     public final E getAndSet(int i, E newValue) {
-        return (E)U.getAndSetObject(array, checkedByteOffset(i), newValue);
+        return (E)AA.getAndSet(array, i, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given
-     * updated value if the current value {@code ==} the expected value.
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
      *
      * @param i the index
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful. False return indicates that
      * the actual value was not equal to the expected value.
      */
-    public final boolean compareAndSet(int i, E expect, E update) {
-        return compareAndSetRaw(checkedByteOffset(i), expect, update);
-    }
-
-    private boolean compareAndSetRaw(long offset, E expect, E update) {
-        return U.compareAndSwapObject(array, offset, expect, update);
+    public final boolean compareAndSet(int i, E expectedValue, E newValue) {
+        return AA.compareAndSet(array, i, expectedValue, newValue);
     }
 
     /**
-     * Atomically sets the element at position {@code i} to the given
-     * updated value if the current value {@code ==} the expected value.
-     *
-     * <p><a href="package-summary.html#weakCompareAndSet">May fail
-     * spuriously and does not provide ordering guarantees</a>, so is
-     * only rarely an appropriate alternative to {@code compareAndSet}.
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
      *
      * @param i the index
-     * @param expect the expected value
-     * @param update the new value
+     * @param expectedValue the expected value
+     * @param newValue the new value
      * @return {@code true} if successful
      */
-    public final boolean weakCompareAndSet(int i, E expect, E update) {
-        return compareAndSet(i, expect, update);
+    public final boolean weakCompareAndSet(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSet(array, i, expectedValue, newValue);
     }
 
     /**
@@ -210,13 +178,14 @@
      * @since 1.8
      */
     public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
-        long offset = checkedByteOffset(i);
-        E prev, next;
-        do {
-            prev = getRaw(offset);
-            next = updateFunction.apply(prev);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return prev;
+        E prev = get(i), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.apply(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
@@ -231,23 +200,25 @@
      * @since 1.8
      */
     public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
-        long offset = checkedByteOffset(i);
-        E prev, next;
-        do {
-            prev = getRaw(offset);
-            next = updateFunction.apply(prev);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return next;
+        E prev = get(i), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.apply(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
      * Atomically updates the element at index {@code i} with the
-     * results of applying the given function to the current and
-     * given values, returning the previous value. The function should
-     * be side-effect-free, since it may be re-applied when attempted
+     * results of applying the given function to the current and given
+     * values, returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
      * updates fail due to contention among threads.  The function is
-     * applied with the current value at index {@code i} as its first
-     * argument, and the given update as the second argument.
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
      *
      * @param i the index
      * @param x the update value
@@ -257,23 +228,25 @@
      */
     public final E getAndAccumulate(int i, E x,
                                     BinaryOperator<E> accumulatorFunction) {
-        long offset = checkedByteOffset(i);
-        E prev, next;
-        do {
-            prev = getRaw(offset);
-            next = accumulatorFunction.apply(prev, x);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return prev;
+        E prev = get(i), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.apply(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
      * Atomically updates the element at index {@code i} with the
-     * results of applying the given function to the current and
-     * given values, returning the updated value. The function should
-     * be side-effect-free, since it may be re-applied when attempted
+     * results of applying the given function to the current and given
+     * values, returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
      * updates fail due to contention among threads.  The function is
-     * applied with the current value at index {@code i} as its first
-     * argument, and the given update as the second argument.
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
      *
      * @param i the index
      * @param x the update value
@@ -283,13 +256,14 @@
      */
     public final E accumulateAndGet(int i, E x,
                                     BinaryOperator<E> accumulatorFunction) {
-        long offset = checkedByteOffset(i);
-        E prev, next;
-        do {
-            prev = getRaw(offset);
-            next = accumulatorFunction.apply(prev, x);
-        } while (!compareAndSetRaw(offset, prev, next));
-        return next;
+        E prev = get(i), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.apply(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
     }
 
     /**
@@ -304,7 +278,7 @@
         StringBuilder b = new StringBuilder();
         b.append('[');
         for (int i = 0; ; i++) {
-            b.append(getRaw(byteOffset(i)));
+            b.append(get(i));
             if (i == iMax)
                 return b.append(']').toString();
             b.append(',').append(' ');
@@ -326,7 +300,199 @@
             throw new java.io.InvalidObjectException("Not array type");
         if (a.getClass() != Object[].class)
             a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
-        U.putObjectVolatile(this, ARRAY, a);
+        Field arrayField = java.security.AccessController.doPrivileged(
+            (java.security.PrivilegedAction<Field>) () -> {
+                try {
+                    Field f = AtomicReferenceArray.class
+                        .getDeclaredField("array");
+                    f.setAccessible(true);
+                    return f;
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }});
+        try {
+            arrayField.set(this, a);
+        } catch (IllegalAccessException e) {
+            throw new Error(e);
+        }
+    }
+
+    // jdk9
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory semantics of reading as if the variable was declared
+     * non-{@code volatile}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final E getPlain(int i) {
+        return (E)AA.get(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory semantics of setting as if the variable was
+     * declared non-{@code volatile} and non-{@code final}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(int i, E newValue) {
+        AA.set(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final E getOpaque(int i) {
+        return (E)AA.getOpaque(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(int i, E newValue) {
+        AA.setOpaque(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final E getAcquire(int i) {
+        return (E)AA.getAcquire(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(int i, E newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final E compareAndExchange(int i, E expectedValue, E newValue) {
+        return (E)AA.compareAndExchange(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final E compareAndExchangeAcquire(int i, E expectedValue, E newValue) {
+        return (E)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final E compareAndExchangeRelease(int i, E expectedValue, E newValue) {
+        return (E)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetVolatile}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
     }
 
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Wed Jul 05 22:00:06 2017 +0200
@@ -42,6 +42,7 @@
 import java.security.PrivilegedExceptionAction;
 import java.util.function.BinaryOperator;
 import java.util.function.UnaryOperator;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 
@@ -168,8 +169,8 @@
     public abstract void lazySet(T obj, V newValue);
 
     /**
-     * Gets the current value held in the field of the given object managed
-     * by this updater.
+     * Returns the current value held in the field of the given object
+     * managed by this updater.
      *
      * @param obj An object whose field to get
      * @return the current value
@@ -284,7 +285,7 @@
 
     private static final class AtomicReferenceFieldUpdaterImpl<T,V>
         extends AtomicReferenceFieldUpdater<T,V> {
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+        private static final Unsafe U = Unsafe.getUnsafe();
         private final long offset;
         /**
          * if field is protected, the subclass constructing updater, else
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,9 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
 /**
  * An {@code AtomicStampedReference} maintains an object reference
  * along with an integer "stamp", that can be updated atomically.
@@ -188,20 +191,19 @@
              casPair(current, Pair.of(expectedReference, newStamp)));
     }
 
-    // Unsafe mechanics
-
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long PAIR;
+    // VarHandle mechanics
+    private static final VarHandle PAIR;
     static {
         try {
-            PAIR = U.objectFieldOffset
-                (AtomicStampedReference.class.getDeclaredField("pair"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
+                                   Pair.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
     }
 
     private boolean casPair(Pair<V> cmp, Pair<V> val) {
-        return U.compareAndSwapObject(this, PAIR, cmp, val);
+        return PAIR.compareAndSet(this, cmp, val);
     }
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/LongAccumulator.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/LongAccumulator.java	Wed Jul 05 22:00:06 2017 +0200
@@ -68,7 +68,7 @@
  * <p>Class {@link LongAdder} provides analogs of the functionality of
  * this class for the common special case of maintaining counts and
  * sums.  The call {@code new LongAdder()} is equivalent to {@code new
- * LongAccumulator((x, y) -> x + y, 0L}.
+ * LongAccumulator((x, y) -> x + y, 0L)}.
  *
  * <p>This class extends {@link Number}, but does <em>not</em> define
  * methods such as {@code equals}, {@code hashCode} and {@code
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,10 +35,13 @@
 
 package java.util.concurrent.atomic;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.Arrays;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.DoubleBinaryOperator;
 import java.util.function.LongBinaryOperator;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A package-local class holding common representation and mechanics
@@ -123,22 +126,21 @@
         volatile long value;
         Cell(long x) { value = x; }
         final boolean cas(long cmp, long val) {
-            return U.compareAndSwapLong(this, VALUE, cmp, val);
+            return VALUE.compareAndSet(this, cmp, val);
         }
         final void reset() {
-            U.putLongVolatile(this, VALUE, 0L);
+            VALUE.setVolatile(this, 0L);
         }
         final void reset(long identity) {
-            U.putLongVolatile(this, VALUE, identity);
+            VALUE.setVolatile(this, identity);
         }
 
-        // Unsafe mechanics
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long VALUE;
+        // VarHandle mechanics
+        private static final VarHandle VALUE;
         static {
             try {
-                VALUE = U.objectFieldOffset
-                    (Cell.class.getDeclaredField("value"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                VALUE = l.findVarHandle(Cell.class, "value", long.class);
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
@@ -174,14 +176,14 @@
      * CASes the base field.
      */
     final boolean casBase(long cmp, long val) {
-        return U.compareAndSwapLong(this, BASE, cmp, val);
+        return BASE.compareAndSet(this, cmp, val);
     }
 
     /**
      * CASes the cellsBusy field from 0 to 1 to acquire lock.
      */
     final boolean casCellsBusy() {
-        return U.compareAndSwapInt(this, CELLSBUSY, 0, 1);
+        return CELLSBUSY.compareAndSet(this, 0, 1);
     }
 
     /**
@@ -371,18 +373,16 @@
         }
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long BASE;
-    private static final long CELLSBUSY;
+    // Unsafe and VarHandle mechanics
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final VarHandle BASE;
+    private static final VarHandle CELLSBUSY;
     private static final long PROBE;
     static {
         try {
-            BASE = U.objectFieldOffset
-                (Striped64.class.getDeclaredField("base"));
-            CELLSBUSY = U.objectFieldOffset
-                (Striped64.class.getDeclaredField("cellsBusy"));
-
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            BASE = l.findVarHandle(Striped64.class, "base", long.class);
+            CELLSBUSY = l.findVarHandle(Striped64.class, "cellsBusy", int.class);
             PROBE = U.objectFieldOffset
                 (Thread.class.getDeclaredField("threadLocalRandomProbe"));
         } catch (ReflectiveOperationException e) {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/package-info.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/package-info.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,26 +35,10 @@
 
 /**
  * A small toolkit of classes that support lock-free thread-safe
- * programming on single variables.  In essence, the classes in this
- * package extend the notion of {@code volatile} values, fields, and
- * array elements to those that also provide an atomic conditional update
- * operation of the form:
- *
- * <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
- *
- * <p>This method (which varies in argument types across different
- * classes) atomically sets a variable to the {@code updateValue} if it
- * currently holds the {@code expectedValue}, reporting {@code true} on
- * success.  The classes in this package also contain methods to get and
- * unconditionally set values, as well as a weaker conditional atomic
- * update operation {@code weakCompareAndSet} described below.
- *
- * <p>The specifications of these methods enable implementations to
- * employ efficient machine-level atomic instructions that are available
- * on contemporary processors.  However on some platforms, support may
- * entail some form of internal locking.  Thus the methods are not
- * strictly guaranteed to be non-blocking --
- * a thread may block transiently before performing the operation.
+ * programming on single variables.  Instances of Atomic classes
+ * maintain values that are accessed and updated using methods
+ * otherwise available for fields using associated atomic {@link
+ * java.lang.invoke.VarHandle} operations.
  *
  * <p>Instances of classes
  * {@link java.util.concurrent.atomic.AtomicBoolean},
@@ -92,45 +76,26 @@
  *   return prev; // return next; for transformAndGet
  * }}</pre>
  *
- * <p>The memory effects for accesses and updates of atomics generally
- * follow the rules for volatiles, as stated in
- * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
- * Chapter 17 of
- * <cite>The Java&trade; Language Specification</cite></a>:
- *
- * <ul>
- *
- *   <li>{@code get} has the memory effects of reading a
- * {@code volatile} variable.
- *
- *   <li>{@code set} has the memory effects of writing (assigning) a
- * {@code volatile} variable.
+ * <p>These classes are not general purpose replacements for {@code
+ * java.lang.Integer} and related classes.  They do <em>not</em>
+ * define methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo}.  Because atomic variables are expected to be mutated,
+ * they are poor choices for hash table keys.
  *
- *   <li>{@code lazySet} has the memory effects of writing (assigning)
- *   a {@code volatile} variable except that it permits reorderings with
- *   subsequent (but not previous) memory actions that do not themselves
- *   impose reordering constraints with ordinary non-{@code volatile}
- *   writes.  Among other usage contexts, {@code lazySet} may apply when
- *   nulling out, for the sake of garbage collection, a reference that is
- *   never accessed again.
+ * <p>The
+ * {@link java.util.concurrent.atomic.AtomicIntegerArray},
+ * {@link java.util.concurrent.atomic.AtomicLongArray}, and
+ * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
+ * further extend atomic operation support to arrays of these types.
+ * These classes are also notable in providing {@code volatile} access
+ * semantics for their array elements.
  *
- *   <li>{@code weakCompareAndSet} atomically reads and conditionally
- *   writes a variable but does <em>not</em>
- *   create any happens-before orderings, so provides no guarantees
- *   with respect to previous or subsequent reads and writes of any
- *   variables other than the target of the {@code weakCompareAndSet}.
- *
- *   <li>{@code compareAndSet}
- *   and all other read-and-update operations such as {@code getAndIncrement}
- *   have the memory effects of both reading and
- *   writing {@code volatile} variables.
- * </ul>
- *
- * <p>In addition to classes representing single values, this package
- * contains <em>Updater</em> classes that can be used to obtain
- * {@code compareAndSet} operations on any selected {@code volatile}
- * field of any selected class.
- *
+ * <p>In addition to classes representing single values and arrays,
+ * this package contains <em>Updater</em> classes that can be used to
+ * obtain {@code compareAndSet} and related operations on any selected
+ * {@code volatile} field of any selected class. These classes
+ * predate the introduction of {@link
+ * java.lang.invoke.VarHandle}, and are of more limited use.
  * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
  * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
  * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
@@ -143,38 +108,6 @@
  * reflection-based setup, less convenient usage, and weaker
  * guarantees.
  *
- * <p>The
- * {@link java.util.concurrent.atomic.AtomicIntegerArray},
- * {@link java.util.concurrent.atomic.AtomicLongArray}, and
- * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
- * further extend atomic operation support to arrays of these types.
- * These classes are also notable in providing {@code volatile} access
- * semantics for their array elements, which is not supported for
- * ordinary arrays.
- *
- * <p id="weakCompareAndSet">The atomic classes also support method
- * {@code weakCompareAndSet}, which has limited applicability.  On some
- * platforms, the weak version may be more efficient than {@code
- * compareAndSet} in the normal case, but differs in that any given
- * invocation of the {@code weakCompareAndSet} method may return {@code
- * false} <em>spuriously</em> (that is, for no apparent reason).  A
- * {@code false} return means only that the operation may be retried if
- * desired, relying on the guarantee that repeated invocation when the
- * variable holds {@code expectedValue} and no other thread is also
- * attempting to set the variable will eventually succeed.  (Such
- * spurious failures may for example be due to memory contention effects
- * that are unrelated to whether the expected and current values are
- * equal.)  Additionally {@code weakCompareAndSet} does not provide
- * ordering guarantees that are usually needed for synchronization
- * control.  However, the method may be useful for updating counters and
- * statistics when such updates are unrelated to the other
- * happens-before orderings of a program.  When a thread sees an update
- * to an atomic variable caused by a {@code weakCompareAndSet}, it does
- * not necessarily see updates to any <em>other</em> variables that
- * occurred before the {@code weakCompareAndSet}.  This may be
- * acceptable when, for example, updating performance statistics, but
- * rarely otherwise.
- *
  * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
  * class associates a single boolean with a reference.  For example, this
  * bit might be used inside a data structure to mean that the object
@@ -185,29 +118,6 @@
  * used for example, to represent version numbers corresponding to
  * series of updates.
  *
- * <p>Atomic classes are designed primarily as building blocks for
- * implementing non-blocking data structures and related infrastructure
- * classes.  The {@code compareAndSet} method is not a general
- * replacement for locking.  It applies only when critical updates for an
- * object are confined to a <em>single</em> variable.
- *
- * <p>Atomic classes are not general purpose replacements for
- * {@code java.lang.Integer} and related classes.  They do <em>not</em>
- * define methods such as {@code equals}, {@code hashCode} and
- * {@code compareTo}.  (Because atomic variables are expected to be
- * mutated, they are poor choices for hash table keys.)  Additionally,
- * classes are provided only for those types that are commonly useful in
- * intended applications.  For example, there is no atomic class for
- * representing {@code byte}.  In those infrequent cases where you would
- * like to do so, you can use an {@code AtomicInteger} to hold
- * {@code byte} values, and cast appropriately.
- *
- * You can also hold floats using
- * {@link java.lang.Float#floatToRawIntBits} and
- * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
- * {@link java.lang.Double#doubleToRawLongBits} and
- * {@link java.lang.Double#longBitsToDouble} conversions.
- *
  * @since 1.5
  */
 package java.util.concurrent.atomic;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent.locks;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
@@ -113,7 +115,7 @@
     protected final void setState(long newState) {
         // Use putLongVolatile instead of ordinary volatile store when
         // using compareAndSwapLong, for sake of some 32bit systems.
-        U.putLongVolatile(this, STATE, newState);
+        STATE.setVolatile(this, newState);
     }
 
     /**
@@ -128,7 +130,7 @@
      *         value was not equal to the expected value.
      */
     protected final boolean compareAndSetState(long expect, long update) {
-        return U.compareAndSwapLong(this, STATE, expect, update);
+        return STATE.compareAndSet(this, expect, update);
     }
 
     // Queuing utilities
@@ -149,7 +151,7 @@
         for (;;) {
             Node oldTail = tail;
             if (oldTail != null) {
-                U.putObject(node, Node.PREV, oldTail);
+                node.setPrevRelaxed(oldTail);
                 if (compareAndSetTail(oldTail, node)) {
                     oldTail.next = node;
                     return oldTail;
@@ -172,7 +174,7 @@
         for (;;) {
             Node oldTail = tail;
             if (oldTail != null) {
-                U.putObject(node, Node.PREV, oldTail);
+                node.setPrevRelaxed(oldTail);
                 if (compareAndSetTail(oldTail, node)) {
                     oldTail.next = node;
                     return node;
@@ -1810,28 +1812,17 @@
         }
     }
 
-    /**
-     * Setup to support compareAndSet. We need to natively implement
-     * this here: For the sake of permitting future enhancements, we
-     * cannot explicitly subclass AtomicLong, which would be
-     * efficient and useful otherwise. So, as the lesser of evils, we
-     * natively implement using hotspot intrinsics API. And while we
-     * are at it, we do the same for other CASable fields (which could
-     * otherwise be done with atomic field updaters).
-     */
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long STATE;
-    private static final long HEAD;
-    private static final long TAIL;
+    // VarHandle mechanics
+    private static final VarHandle STATE;
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
 
     static {
         try {
-            STATE = U.objectFieldOffset
-                (AbstractQueuedLongSynchronizer.class.getDeclaredField("state"));
-            HEAD = U.objectFieldOffset
-                (AbstractQueuedLongSynchronizer.class.getDeclaredField("head"));
-            TAIL = U.objectFieldOffset
-                (AbstractQueuedLongSynchronizer.class.getDeclaredField("tail"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "state", long.class);
+            HEAD = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "head", Node.class);
+            TAIL = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "tail", Node.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
@@ -1846,7 +1837,7 @@
      */
     private final void initializeSyncQueue() {
         Node h;
-        if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+        if (HEAD.compareAndSet(this, null, (h = new Node())))
             tail = h;
     }
 
@@ -1854,6 +1845,6 @@
      * CASes tail field.
      */
     private final boolean compareAndSetTail(Node expect, Node update) {
-        return U.compareAndSwapObject(this, TAIL, expect, update);
+        return TAIL.compareAndSet(this, expect, update);
     }
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,11 +35,12 @@
 
 package java.util.concurrent.locks;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
-import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
  * Provides a framework for implementing blocking locks and related
@@ -506,40 +507,41 @@
         /** Constructor used by addWaiter. */
         Node(Node nextWaiter) {
             this.nextWaiter = nextWaiter;
-            U.putObject(this, THREAD, Thread.currentThread());
+            THREAD.set(this, Thread.currentThread());
         }
 
         /** Constructor used by addConditionWaiter. */
         Node(int waitStatus) {
-            U.putInt(this, WAITSTATUS, waitStatus);
-            U.putObject(this, THREAD, Thread.currentThread());
+            WAITSTATUS.set(this, waitStatus);
+            THREAD.set(this, Thread.currentThread());
         }
 
         /** CASes waitStatus field. */
         final boolean compareAndSetWaitStatus(int expect, int update) {
-            return U.compareAndSwapInt(this, WAITSTATUS, expect, update);
+            return WAITSTATUS.compareAndSet(this, expect, update);
         }
 
         /** CASes next field. */
         final boolean compareAndSetNext(Node expect, Node update) {
-            return U.compareAndSwapObject(this, NEXT, expect, update);
+            return NEXT.compareAndSet(this, expect, update);
+        }
+
+        final void setPrevRelaxed(Node p) {
+            PREV.set(this, p);
         }
 
-        private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-        private static final long NEXT;
-        static final long PREV;
-        private static final long THREAD;
-        private static final long WAITSTATUS;
+        // VarHandle mechanics
+        private static final VarHandle NEXT;
+        private static final VarHandle PREV;
+        private static final VarHandle THREAD;
+        private static final VarHandle WAITSTATUS;
         static {
             try {
-                NEXT = U.objectFieldOffset
-                    (Node.class.getDeclaredField("next"));
-                PREV = U.objectFieldOffset
-                    (Node.class.getDeclaredField("prev"));
-                THREAD = U.objectFieldOffset
-                    (Node.class.getDeclaredField("thread"));
-                WAITSTATUS = U.objectFieldOffset
-                    (Node.class.getDeclaredField("waitStatus"));
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                NEXT = l.findVarHandle(Node.class, "next", Node.class);
+                PREV = l.findVarHandle(Node.class, "prev", Node.class);
+                THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
+                WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
@@ -595,7 +597,7 @@
      *         value was not equal to the expected value.
      */
     protected final boolean compareAndSetState(int expect, int update) {
-        return U.compareAndSwapInt(this, STATE, expect, update);
+        return STATE.compareAndSet(this, expect, update);
     }
 
     // Queuing utilities
@@ -616,7 +618,7 @@
         for (;;) {
             Node oldTail = tail;
             if (oldTail != null) {
-                U.putObject(node, Node.PREV, oldTail);
+                node.setPrevRelaxed(oldTail);
                 if (compareAndSetTail(oldTail, node)) {
                     oldTail.next = node;
                     return oldTail;
@@ -639,7 +641,7 @@
         for (;;) {
             Node oldTail = tail;
             if (oldTail != null) {
-                U.putObject(node, Node.PREV, oldTail);
+                node.setPrevRelaxed(oldTail);
                 if (compareAndSetTail(oldTail, node)) {
                     oldTail.next = node;
                     return node;
@@ -887,7 +889,6 @@
      * @param arg the acquire argument
      * @return {@code true} if interrupted while waiting
      */
-    @ReservedStackAccess
     final boolean acquireQueued(final Node node, int arg) {
         try {
             boolean interrupted = false;
@@ -1220,7 +1221,6 @@
      *        {@link #tryAcquire} but is otherwise uninterpreted and
      *        can represent anything you like.
      */
-    @ReservedStackAccess
     public final void acquire(int arg) {
         if (!tryAcquire(arg) &&
             acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
@@ -1284,7 +1284,6 @@
      *        can represent anything you like.
      * @return the value returned from {@link #tryRelease}
      */
-    @ReservedStackAccess
     public final boolean release(int arg) {
         if (tryRelease(arg)) {
             Node h = head;
@@ -1365,7 +1364,6 @@
      *        and can represent anything you like.
      * @return the value returned from {@link #tryReleaseShared}
      */
-    @ReservedStackAccess
     public final boolean releaseShared(int arg) {
         if (tryReleaseShared(arg)) {
             doReleaseShared();
@@ -2279,28 +2277,17 @@
         }
     }
 
-    /**
-     * Setup to support compareAndSet. We need to natively implement
-     * this here: For the sake of permitting future enhancements, we
-     * cannot explicitly subclass AtomicInteger, which would be
-     * efficient and useful otherwise. So, as the lesser of evils, we
-     * natively implement using hotspot intrinsics API. And while we
-     * are at it, we do the same for other CASable fields (which could
-     * otherwise be done with atomic field updaters).
-     */
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long STATE;
-    private static final long HEAD;
-    private static final long TAIL;
+    // VarHandle mechanics
+    private static final VarHandle STATE;
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
 
     static {
         try {
-            STATE = U.objectFieldOffset
-                (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
-            HEAD = U.objectFieldOffset
-                (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
-            TAIL = U.objectFieldOffset
-                (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(AbstractQueuedSynchronizer.class, "state", int.class);
+            HEAD = l.findVarHandle(AbstractQueuedSynchronizer.class, "head", Node.class);
+            TAIL = l.findVarHandle(AbstractQueuedSynchronizer.class, "tail", Node.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
@@ -2315,7 +2302,7 @@
      */
     private final void initializeSyncQueue() {
         Node h;
-        if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+        if (HEAD.compareAndSet(this, null, (h = new Node())))
             tail = h;
     }
 
@@ -2323,6 +2310,6 @@
      * CASes tail field.
      */
     private final boolean compareAndSetTail(Node expect, Node update) {
-        return U.compareAndSwapObject(this, TAIL, expect, update);
+        return TAIL.compareAndSet(this, expect, update);
     }
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/Condition.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/Condition.java	Wed Jul 05 22:00:06 2017 +0200
@@ -396,7 +396,6 @@
      * re-acquire the lock associated with this condition. When the
      * thread returns it is <em>guaranteed</em> to hold this lock.
      *
-     *
      * <p>If the current thread:
      * <ul>
      * <li>has its interrupted status set on entry to this method; or
@@ -408,7 +407,6 @@
      * case, whether or not the test for interruption occurs before the lock
      * is released.
      *
-     *
      * <p>The return value indicates whether the deadline has elapsed,
      * which can be used as follows:
      * <pre> {@code
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,8 @@
 
 package java.util.concurrent.locks;
 
+import jdk.internal.misc.Unsafe;
+
 /**
  * Basic thread blocking primitives for creating locks and other
  * synchronization classes.
@@ -405,16 +407,30 @@
         return r;
     }
 
+    /**
+     * Returns the thread id for the given thread.  We must access
+     * this directly rather than via method Thread.getId() because
+     * getId() is not final, and has been known to be overridden in
+     * ways that do not preserve unique mappings.
+     */
+    static final long getThreadId(Thread thread) {
+        return U.getLongVolatile(thread, TID);
+    }
+
     // Hotspot implementation via intrinsics API
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+    private static final Unsafe U = Unsafe.getUnsafe();
     private static final long PARKBLOCKER;
     private static final long SECONDARY;
+    private static final long TID;
     static {
         try {
             PARKBLOCKER = U.objectFieldOffset
                 (Thread.class.getDeclaredField("parkBlocker"));
             SECONDARY = U.objectFieldOffset
                 (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+            TID = U.objectFieldOffset
+                (Thread.class.getDeclaredField("tid"));
+
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReadWriteLock.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReadWriteLock.java	Wed Jul 05 22:00:06 2017 +0200
@@ -79,7 +79,6 @@
  * and measurement will establish whether the use of a read-write lock is
  * suitable for your application.
  *
- *
  * <p>Although the basic operation of a read-write lock is straight-forward,
  * there are many policy decisions that an implementation must make, which
  * may affect the effectiveness of the read-write lock in a given application.
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java	Wed Jul 05 22:00:06 2017 +0200
@@ -119,12 +119,6 @@
         private static final long serialVersionUID = -5179523762034025860L;
 
         /**
-         * Performs {@link Lock#lock}. The main reason for subclassing
-         * is to allow fast path for nonfair version.
-         */
-        abstract void lock();
-
-        /**
          * Performs non-fair tryLock.  tryAcquire is implemented in
          * subclasses, but both need nonfair try for trylock method.
          */
@@ -201,19 +195,6 @@
      */
     static final class NonfairSync extends Sync {
         private static final long serialVersionUID = 7316153563782823691L;
-
-        /**
-         * Performs lock.  Try immediate barge, backing up to normal
-         * acquire on failure.
-         */
-        @ReservedStackAccess
-        final void lock() {
-            if (compareAndSetState(0, 1))
-                setExclusiveOwnerThread(Thread.currentThread());
-            else
-                acquire(1);
-        }
-
         protected final boolean tryAcquire(int acquires) {
             return nonfairTryAcquire(acquires);
         }
@@ -224,11 +205,6 @@
      */
     static final class FairSync extends Sync {
         private static final long serialVersionUID = -3000897897090466540L;
-
-        final void lock() {
-            acquire(1);
-        }
-
         /**
          * Fair version of tryAcquire.  Don't grant access unless
          * recursive call or no waiters or is first.
@@ -288,7 +264,7 @@
      * at which time the lock hold count is set to one.
      */
     public void lock() {
-        sync.lock();
+        sync.acquire(1);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java	Wed Jul 05 22:00:06 2017 +0200
@@ -37,6 +37,7 @@
 
 import java.util.Collection;
 import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
  * An implementation of {@link ReadWriteLock} supporting similar
@@ -278,7 +279,7 @@
         static final class HoldCounter {
             int count;          // initially 0
             // Use id, not reference, to avoid garbage retention
-            final long tid = getThreadId(Thread.currentThread());
+            final long tid = LockSupport.getThreadId(Thread.currentThread());
         }
 
         /**
@@ -367,7 +368,7 @@
          * both read and write holds that are all released during a
          * condition wait and re-established in tryAcquire.
          */
-
+        @ReservedStackAccess
         protected final boolean tryRelease(int releases) {
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
@@ -379,6 +380,7 @@
             return free;
         }
 
+        @ReservedStackAccess
         protected final boolean tryAcquire(int acquires) {
             /*
              * Walkthrough:
@@ -411,6 +413,7 @@
             return true;
         }
 
+        @ReservedStackAccess
         protected final boolean tryReleaseShared(int unused) {
             Thread current = Thread.currentThread();
             if (firstReader == current) {
@@ -421,7 +424,8 @@
                     firstReaderHoldCount--;
             } else {
                 HoldCounter rh = cachedHoldCounter;
-                if (rh == null || rh.tid != getThreadId(current))
+                if (rh == null ||
+                    rh.tid != LockSupport.getThreadId(current))
                     rh = readHolds.get();
                 int count = rh.count;
                 if (count <= 1) {
@@ -447,6 +451,7 @@
                 "attempt to unlock read lock, not locked by current thread");
         }
 
+        @ReservedStackAccess
         protected final int tryAcquireShared(int unused) {
             /*
              * Walkthrough:
@@ -479,7 +484,8 @@
                     firstReaderHoldCount++;
                 } else {
                     HoldCounter rh = cachedHoldCounter;
-                    if (rh == null || rh.tid != getThreadId(current))
+                    if (rh == null ||
+                        rh.tid != LockSupport.getThreadId(current))
                         cachedHoldCounter = rh = readHolds.get();
                     else if (rh.count == 0)
                         readHolds.set(rh);
@@ -516,7 +522,8 @@
                     } else {
                         if (rh == null) {
                             rh = cachedHoldCounter;
-                            if (rh == null || rh.tid != getThreadId(current)) {
+                            if (rh == null ||
+                                rh.tid != LockSupport.getThreadId(current)) {
                                 rh = readHolds.get();
                                 if (rh.count == 0)
                                     readHolds.remove();
@@ -537,7 +544,8 @@
                     } else {
                         if (rh == null)
                             rh = cachedHoldCounter;
-                        if (rh == null || rh.tid != getThreadId(current))
+                        if (rh == null ||
+                            rh.tid != LockSupport.getThreadId(current))
                             rh = readHolds.get();
                         else if (rh.count == 0)
                             readHolds.set(rh);
@@ -554,6 +562,7 @@
          * This is identical in effect to tryAcquire except for lack
          * of calls to writerShouldBlock.
          */
+        @ReservedStackAccess
         final boolean tryWriteLock() {
             Thread current = Thread.currentThread();
             int c = getState();
@@ -575,6 +584,7 @@
          * This is identical in effect to tryAcquireShared except for
          * lack of calls to readerShouldBlock.
          */
+        @ReservedStackAccess
         final boolean tryReadLock() {
             Thread current = Thread.currentThread();
             for (;;) {
@@ -593,7 +603,8 @@
                         firstReaderHoldCount++;
                     } else {
                         HoldCounter rh = cachedHoldCounter;
-                        if (rh == null || rh.tid != getThreadId(current))
+                        if (rh == null ||
+                            rh.tid != LockSupport.getThreadId(current))
                             cachedHoldCounter = rh = readHolds.get();
                         else if (rh.count == 0)
                             readHolds.set(rh);
@@ -644,7 +655,7 @@
                 return firstReaderHoldCount;
 
             HoldCounter rh = cachedHoldCounter;
-            if (rh != null && rh.tid == getThreadId(current))
+            if (rh != null && rh.tid == LockSupport.getThreadId(current))
                 return rh.count;
 
             int count = readHolds.get().count;
@@ -1490,26 +1501,4 @@
             "[Write locks = " + w + ", Read locks = " + r + "]";
     }
 
-    /**
-     * Returns the thread id for the given thread.  We must access
-     * this directly rather than via method Thread.getId() because
-     * getId() is not final, and has been known to be overridden in
-     * ways that do not preserve unique mappings.
-     */
-    static final long getThreadId(Thread thread) {
-        return U.getLongVolatile(thread, TID);
-    }
-
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long TID;
-    static {
-        try {
-            TID = U.objectFieldOffset
-                (Thread.class.getDeclaredField("tid"));
-        } catch (ReflectiveOperationException e) {
-            throw new Error(e);
-        }
-    }
-
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,7 +35,10 @@
 
 package java.util.concurrent.locks;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
  * A capability-based lock with three modes for controlling read/write
@@ -108,6 +111,10 @@
  * into initial unlocked state, so they are not useful for remote
  * locking.
  *
+ * <p>Like {@link java.util.concurrent.Semaphore Semaphore}, but unlike most
+ * {@link Lock} implementations, StampedLocks have no notion of ownership.
+ * Locks acquired in one thread can be released or converted in another.
+ *
  * <p>The scheduling policy of StampedLock does not consistently
  * prefer readers over writers or vice versa.  All "try" methods are
  * best-effort and do not necessarily conform to any scheduling or
@@ -126,7 +133,7 @@
  * in a class that maintains simple two-dimensional points. The sample
  * code illustrates some try/catch conventions even though they are
  * not strictly needed here because no exceptions can occur in their
- * bodies.<br>
+ * bodies.
  *
  * <pre> {@code
  * class Point {
@@ -234,9 +241,7 @@
      * used in the acquire methods to reduce (increasingly expensive)
      * context switching while also avoiding sustained memory
      * thrashing among many threads.  We limit spins to the head of
-     * queue. A thread spin-waits up to SPINS times (where each
-     * iteration decreases spin count with 50% probability) before
-     * blocking. If, upon wakening it fails to obtain lock, and is
+     * queue. If, upon wakening, a thread fails to obtain lock, and is
      * still (or becomes) the first waiting thread (which indicates
      * that some other thread barged and obtained lock), it escalates
      * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
@@ -251,8 +256,12 @@
      * method validate()) requires stricter ordering rules than apply
      * to normal volatile reads (of "state").  To force orderings of
      * reads before a validation and the validation itself in those
-     * cases where this is not already forced, we use
-     * Unsafe.loadFence.
+     * cases where this is not already forced, we use acquireFence.
+     * Unlike in that paper, we allow writers to use plain writes.
+     * One would not expect reorderings of such writes with the lock
+     * acquisition CAS because there is a "control dependency", but it
+     * is theoretically possible, so we additionally add a
+     * storeStoreFence after lock acquisition CAS.
      *
      * The memory layout keeps lock state and queue pointers together
      * (normally on the same cache line). This usually works well for
@@ -290,7 +299,20 @@
     private static final long ABITS = RBITS | WBIT;
     private static final long SBITS = ~RBITS; // note overlap with ABITS
 
-    // Initial value for lock state; avoid failure value zero
+    /*
+     * 3 stamp modes can be distinguished by examining (m = stamp & ABITS):
+     * write mode: m == WBIT
+     * optimistic read mode: m == 0L (even when read lock is held)
+     * read mode: m > 0L && m <= RFULL (the stamp is a copy of state, but the
+     * read hold count in the stamp is unused other than to determine mode)
+     *
+     * This differs slightly from the encoding of state:
+     * (state & ABITS) == 0L indicates the lock is currently unlocked.
+     * (state & ABITS) == RBITS is a special transient value
+     * indicating spin-locked to manipulate reader bits overflow.
+     */
+
+    /** Initial value for lock state; avoids failure value zero. */
     private static final long ORIGIN = WBIT << 1;
 
     // Special value from cancelled acquire methods so caller can throw IE
@@ -337,30 +359,42 @@
         state = ORIGIN;
     }
 
+    private boolean casState(long expectedValue, long newValue) {
+        return STATE.compareAndSet(this, expectedValue, newValue);
+    }
+
+    private long tryWriteLock(long s) {
+        // assert (s & ABITS) == 0L;
+        long next;
+        if (casState(s, next = s | WBIT)) {
+            VarHandle.storeStoreFence();
+            return next;
+        }
+        return 0L;
+    }
+
     /**
      * Exclusively acquires the lock, blocking if necessary
      * until available.
      *
-     * @return a stamp that can be used to unlock or convert mode
+     * @return a write stamp that can be used to unlock or convert mode
      */
+    @ReservedStackAccess
     public long writeLock() {
-        long s, next;  // bypass acquireWrite in fully unlocked case only
-        return ((((s = state) & ABITS) == 0L &&
-                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
-                next : acquireWrite(false, 0L));
+        long next;
+        return ((next = tryWriteLock()) != 0L) ? next : acquireWrite(false, 0L);
     }
 
     /**
      * Exclusively acquires the lock if it is immediately available.
      *
-     * @return a stamp that can be used to unlock or convert mode,
+     * @return a write stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
+    @ReservedStackAccess
     public long tryWriteLock() {
-        long s, next;
-        return ((((s = state) & ABITS) == 0L &&
-                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
-                next : 0L);
+        long s;
+        return (((s = state) & ABITS) == 0L) ? tryWriteLock(s) : 0L;
     }
 
     /**
@@ -371,7 +405,7 @@
      *
      * @param time the maximum time to wait for the lock
      * @param unit the time unit of the {@code time} argument
-     * @return a stamp that can be used to unlock or convert mode,
+     * @return a write stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
@@ -399,10 +433,11 @@
      * Behavior under interruption matches that specified
      * for method {@link Lock#lockInterruptibly()}.
      *
-     * @return a stamp that can be used to unlock or convert mode
+     * @return a write stamp that can be used to unlock or convert mode
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
+    @ReservedStackAccess
     public long writeLockInterruptibly() throws InterruptedException {
         long next;
         if (!Thread.interrupted() &&
@@ -415,33 +450,37 @@
      * Non-exclusively acquires the lock, blocking if necessary
      * until available.
      *
-     * @return a stamp that can be used to unlock or convert mode
+     * @return a read stamp that can be used to unlock or convert mode
      */
+    @ReservedStackAccess
     public long readLock() {
-        long s = state, next;  // bypass acquireRead on common uncontended case
-        return ((whead == wtail && (s & ABITS) < RFULL &&
-                 U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
-                next : acquireRead(false, 0L));
+        long s, next;
+        // bypass acquireRead on common uncontended case
+        return (whead == wtail
+                && ((s = state) & ABITS) < RFULL
+                && casState(s, next = s + RUNIT))
+            ? next
+            : acquireRead(false, 0L);
     }
 
     /**
      * Non-exclusively acquires the lock if it is immediately available.
      *
-     * @return a stamp that can be used to unlock or convert mode,
+     * @return a read stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
+    @ReservedStackAccess
     public long tryReadLock() {
-        for (;;) {
-            long s, m, next;
-            if ((m = (s = state) & ABITS) == WBIT)
-                return 0L;
-            else if (m < RFULL) {
-                if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+        long s, m, next;
+        while ((m = (s = state) & ABITS) != WBIT) {
+            if (m < RFULL) {
+                if (casState(s, next = s + RUNIT))
                     return next;
             }
             else if ((next = tryIncReaderOverflow(s)) != 0L)
                 return next;
         }
+        return 0L;
     }
 
     /**
@@ -452,11 +491,12 @@
      *
      * @param time the maximum time to wait for the lock
      * @param unit the time unit of the {@code time} argument
-     * @return a stamp that can be used to unlock or convert mode,
+     * @return a read stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
+    @ReservedStackAccess
     public long tryReadLock(long time, TimeUnit unit)
         throws InterruptedException {
         long s, m, next, deadline;
@@ -464,7 +504,7 @@
         if (!Thread.interrupted()) {
             if ((m = (s = state) & ABITS) != WBIT) {
                 if (m < RFULL) {
-                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+                    if (casState(s, next = s + RUNIT))
                         return next;
                 }
                 else if ((next = tryIncReaderOverflow(s)) != 0L)
@@ -486,14 +526,20 @@
      * Behavior under interruption matches that specified
      * for method {@link Lock#lockInterruptibly()}.
      *
-     * @return a stamp that can be used to unlock or convert mode
+     * @return a read stamp that can be used to unlock or convert mode
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    public long readLockInterruptibly() throws InterruptedException {
-        long next;
-        if (!Thread.interrupted() &&
-            (next = acquireRead(true, 0L)) != INTERRUPTED)
+    @ReservedStackAccess
+        public long readLockInterruptibly() throws InterruptedException {
+        long s, next;
+        if (!Thread.interrupted()
+            // bypass acquireRead on common uncontended case
+            && ((whead == wtail
+                 && ((s = state) & ABITS) < RFULL
+                 && casState(s, next = s + RUNIT))
+                ||
+                (next = acquireRead(true, 0L)) != INTERRUPTED))
             return next;
         throw new InterruptedException();
     }
@@ -502,7 +548,7 @@
      * Returns a stamp that can later be validated, or zero
      * if exclusively locked.
      *
-     * @return a stamp, or zero if exclusively locked
+     * @return a valid optimistic read stamp, or zero if exclusively locked
      */
     public long tryOptimisticRead() {
         long s;
@@ -522,11 +568,29 @@
      * since issuance of the given stamp; else false
      */
     public boolean validate(long stamp) {
-        U.loadFence();
+        VarHandle.acquireFence();
         return (stamp & SBITS) == (state & SBITS);
     }
 
     /**
+     * Returns an unlocked state, incrementing the version and
+     * avoiding special failure value 0L.
+     *
+     * @param s a write-locked state (or stamp)
+     */
+    private static long unlockWriteState(long s) {
+        return ((s += WBIT) == 0L) ? ORIGIN : s;
+    }
+
+    private long unlockWriteInternal(long s) {
+        long next; WNode h;
+        STATE.setVolatile(this, next = unlockWriteState(s));
+        if ((h = whead) != null && h.status != 0)
+            release(h);
+        return next;
+    }
+
+    /**
      * If the lock state matches the given stamp, releases the
      * exclusive lock.
      *
@@ -534,13 +598,11 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
+    @ReservedStackAccess
     public void unlockWrite(long stamp) {
-        WNode h;
         if (state != stamp || (stamp & WBIT) == 0L)
             throw new IllegalMonitorStateException();
-        U.putLongVolatile(this, STATE, (stamp += WBIT) == 0L ? ORIGIN : stamp);
-        if ((h = whead) != null && h.status != 0)
-            release(h);
+        unlockWriteInternal(stamp);
     }
 
     /**
@@ -551,22 +613,23 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
+    @ReservedStackAccess
     public void unlockRead(long stamp) {
         long s, m; WNode h;
-        for (;;) {
-            if (((s = state) & SBITS) != (stamp & SBITS) ||
-                (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
-                throw new IllegalMonitorStateException();
+        while (((s = state) & SBITS) == (stamp & SBITS)
+               && (stamp & RBITS) > 0L
+               && ((m = s & RBITS) > 0L)) {
             if (m < RFULL) {
-                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                if (casState(s, s - RUNIT)) {
                     if (m == RUNIT && (h = whead) != null && h.status != 0)
                         release(h);
-                    break;
+                    return;
                 }
             }
             else if (tryDecReaderOverflow(s) != 0L)
-                break;
+                return;
         }
+        throw new IllegalMonitorStateException();
     }
 
     /**
@@ -577,32 +640,12 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
+    @ReservedStackAccess
     public void unlock(long stamp) {
-        long a = stamp & ABITS, m, s; WNode h;
-        while (((s = state) & SBITS) == (stamp & SBITS)) {
-            if ((m = s & ABITS) == 0L)
-                break;
-            else if (m == WBIT) {
-                if (a != m)
-                    break;
-                U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
-                if ((h = whead) != null && h.status != 0)
-                    release(h);
-                return;
-            }
-            else if (a == 0L || a >= WBIT)
-                break;
-            else if (m < RFULL) {
-                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
-                    return;
-                }
-            }
-            else if (tryDecReaderOverflow(s) != 0L)
-                return;
-        }
-        throw new IllegalMonitorStateException();
+        if ((stamp & WBIT) != 0L)
+            unlockWrite(stamp);
+        else
+            unlockRead(stamp);
     }
 
     /**
@@ -623,7 +666,7 @@
             if ((m = s & ABITS) == 0L) {
                 if (a != 0L)
                     break;
-                if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
+                if ((next = tryWriteLock(s)) != 0L)
                     return next;
             }
             else if (m == WBIT) {
@@ -632,9 +675,10 @@
                 return stamp;
             }
             else if (m == RUNIT && a != 0L) {
-                if (U.compareAndSwapLong(this, STATE, s,
-                                         next = s - RUNIT + WBIT))
+                if (casState(s, next = s - RUNIT + WBIT)) {
+                    VarHandle.storeStoreFence();
                     return next;
+                }
             }
             else
                 break;
@@ -654,30 +698,32 @@
      * @return a valid read stamp, or zero on failure
      */
     public long tryConvertToReadLock(long stamp) {
-        long a = stamp & ABITS, m, s, next; WNode h;
+        long a, s, next; WNode h;
         while (((s = state) & SBITS) == (stamp & SBITS)) {
-            if ((m = s & ABITS) == 0L) {
-                if (a != 0L)
+            if ((a = stamp & ABITS) >= WBIT) {
+                // write stamp
+                if (s != stamp)
                     break;
-                else if (m < RFULL) {
-                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+                STATE.setVolatile(this, next = unlockWriteState(s) + RUNIT);
+                if ((h = whead) != null && h.status != 0)
+                    release(h);
+                return next;
+            }
+            else if (a == 0L) {
+                // optimistic read stamp
+                if ((s & ABITS) < RFULL) {
+                    if (casState(s, next = s + RUNIT))
                         return next;
                 }
                 else if ((next = tryIncReaderOverflow(s)) != 0L)
                     return next;
             }
-            else if (m == WBIT) {
-                if (a != m)
+            else {
+                // already a read stamp
+                if ((s & ABITS) == 0L)
                     break;
-                U.putLongVolatile(this, STATE, next = s + (WBIT + RUNIT));
-                if ((h = whead) != null && h.status != 0)
-                    release(h);
-                return next;
+                return stamp;
             }
-            else if (a != 0L && a < WBIT)
-                return stamp;
-            else
-                break;
         }
         return 0L;
     }
@@ -693,29 +739,22 @@
      * @return a valid optimistic read stamp, or zero on failure
      */
     public long tryConvertToOptimisticRead(long stamp) {
-        long a = stamp & ABITS, m, s, next; WNode h;
-        U.loadFence();
-        for (;;) {
-            if (((s = state) & SBITS) != (stamp & SBITS))
-                break;
-            if ((m = s & ABITS) == 0L) {
-                if (a != 0L)
+        long a, m, s, next; WNode h;
+        VarHandle.acquireFence();
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((a = stamp & ABITS) >= WBIT) {
+                // write stamp
+                if (s != stamp)
                     break;
-                return s;
+                return unlockWriteInternal(s);
             }
-            else if (m == WBIT) {
-                if (a != m)
-                    break;
-                U.putLongVolatile(this, STATE,
-                                  next = (s += WBIT) == 0L ? ORIGIN : s);
-                if ((h = whead) != null && h.status != 0)
-                    release(h);
-                return next;
-            }
-            else if (a == 0L || a >= WBIT)
+            else if (a == 0L)
+                // already an optimistic read stamp
+                return stamp;
+            else if ((m = s & ABITS) == 0L) // invalid read stamp
                 break;
             else if (m < RFULL) {
-                if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
+                if (casState(s, next = s - RUNIT)) {
                     if (m == RUNIT && (h = whead) != null && h.status != 0)
                         release(h);
                     return next & SBITS;
@@ -734,12 +773,11 @@
      *
      * @return {@code true} if the lock was held, else false
      */
+    @ReservedStackAccess
     public boolean tryUnlockWrite() {
-        long s; WNode h;
+        long s;
         if (((s = state) & WBIT) != 0L) {
-            U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
-            if ((h = whead) != null && h.status != 0)
-                release(h);
+            unlockWriteInternal(s);
             return true;
         }
         return false;
@@ -752,11 +790,12 @@
      *
      * @return {@code true} if the read lock was held, else false
      */
+    @ReservedStackAccess
     public boolean tryUnlockRead() {
         long s, m; WNode h;
         while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
             if (m < RFULL) {
-                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                if (casState(s, s - RUNIT)) {
                     if (m == RUNIT && (h = whead) != null && h.status != 0)
                         release(h);
                     return true;
@@ -832,32 +871,30 @@
      * Returns a plain {@link Lock} view of this StampedLock in which
      * the {@link Lock#lock} method is mapped to {@link #readLock},
      * and similarly for other methods. The returned Lock does not
-     * support a {@link Condition}; method {@link
-     * Lock#newCondition()} throws {@code
-     * UnsupportedOperationException}.
+     * support a {@link Condition}; method {@link Lock#newCondition()}
+     * throws {@code UnsupportedOperationException}.
      *
      * @return the lock
      */
     public Lock asReadLock() {
         ReadLockView v;
-        return ((v = readLockView) != null ? v :
-                (readLockView = new ReadLockView()));
+        if ((v = readLockView) != null) return v;
+        return readLockView = new ReadLockView();
     }
 
     /**
      * Returns a plain {@link Lock} view of this StampedLock in which
      * the {@link Lock#lock} method is mapped to {@link #writeLock},
      * and similarly for other methods. The returned Lock does not
-     * support a {@link Condition}; method {@link
-     * Lock#newCondition()} throws {@code
-     * UnsupportedOperationException}.
+     * support a {@link Condition}; method {@link Lock#newCondition()}
+     * throws {@code UnsupportedOperationException}.
      *
      * @return the lock
      */
     public Lock asWriteLock() {
         WriteLockView v;
-        return ((v = writeLockView) != null ? v :
-                (writeLockView = new WriteLockView()));
+        if ((v = writeLockView) != null) return v;
+        return writeLockView = new WriteLockView();
     }
 
     /**
@@ -870,8 +907,8 @@
      */
     public ReadWriteLock asReadWriteLock() {
         ReadWriteLockView v;
-        return ((v = readWriteLockView) != null ? v :
-                (readWriteLockView = new ReadWriteLockView()));
+        if ((v = readWriteLockView) != null) return v;
+        return readWriteLockView = new ReadWriteLockView();
     }
 
     // view classes
@@ -917,35 +954,32 @@
     // Needed because view-class lock methods throw away stamps.
 
     final void unstampedUnlockWrite() {
-        WNode h; long s;
+        long s;
         if (((s = state) & WBIT) == 0L)
             throw new IllegalMonitorStateException();
-        U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
-        if ((h = whead) != null && h.status != 0)
-            release(h);
+        unlockWriteInternal(s);
     }
 
     final void unstampedUnlockRead() {
-        for (;;) {
-            long s, m; WNode h;
-            if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
-                throw new IllegalMonitorStateException();
-            else if (m < RFULL) {
-                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+        long s, m; WNode h;
+        while ((m = (s = state) & RBITS) > 0L) {
+            if (m < RFULL) {
+                if (casState(s, s - RUNIT)) {
                     if (m == RUNIT && (h = whead) != null && h.status != 0)
                         release(h);
-                    break;
+                    return;
                 }
             }
             else if (tryDecReaderOverflow(s) != 0L)
-                break;
+                return;
         }
+        throw new IllegalMonitorStateException();
     }
 
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
         s.defaultReadObject();
-        U.putLongVolatile(this, STATE, ORIGIN); // reset to unlocked state
+        STATE.setVolatile(this, ORIGIN); // reset to unlocked state
     }
 
     // internals
@@ -961,15 +995,16 @@
     private long tryIncReaderOverflow(long s) {
         // assert (s & ABITS) >= RFULL;
         if ((s & ABITS) == RFULL) {
-            if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
+            if (casState(s, s | RBITS)) {
                 ++readerOverflow;
-                U.putLongVolatile(this, STATE, s);
+                STATE.setVolatile(this, s);
                 return s;
             }
         }
-        else if ((LockSupport.nextSecondarySeed() &
-                  OVERFLOW_YIELD_RATE) == 0)
+        else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
             Thread.yield();
+        else
+            Thread.onSpinWait();
         return 0L;
     }
 
@@ -982,7 +1017,7 @@
     private long tryDecReaderOverflow(long s) {
         // assert (s & ABITS) >= RFULL;
         if ((s & ABITS) == RFULL) {
-            if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
+            if (casState(s, s | RBITS)) {
                 int r; long next;
                 if ((r = readerOverflow) > 0) {
                     readerOverflow = r - 1;
@@ -990,13 +1025,14 @@
                 }
                 else
                     next = s - RUNIT;
-                U.putLongVolatile(this, STATE, next);
+                STATE.setVolatile(this, next);
                 return next;
             }
         }
-        else if ((LockSupport.nextSecondarySeed() &
-                  OVERFLOW_YIELD_RATE) == 0)
+        else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
             Thread.yield();
+        else
+            Thread.onSpinWait();
         return 0L;
     }
 
@@ -1010,14 +1046,14 @@
     private void release(WNode h) {
         if (h != null) {
             WNode q; Thread w;
-            U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
+            WSTATUS.compareAndSet(h, WAITING, 0);
             if ((q = h.next) == null || q.status == CANCELLED) {
                 for (WNode t = wtail; t != null && t != h; t = t.prev)
                     if (t.status <= 0)
                         q = t;
             }
             if (q != null && (w = q.thread) != null)
-                U.unpark(w);
+                LockSupport.unpark(w);
         }
     }
 
@@ -1035,25 +1071,25 @@
         for (int spins = -1;;) { // spin while enqueuing
             long m, s, ns;
             if ((m = (s = state) & ABITS) == 0L) {
-                if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
+                if ((ns = tryWriteLock(s)) != 0L)
                     return ns;
             }
             else if (spins < 0)
                 spins = (m == WBIT && wtail == whead) ? SPINS : 0;
             else if (spins > 0) {
-                if (LockSupport.nextSecondarySeed() >= 0)
-                    --spins;
+                --spins;
+                Thread.onSpinWait();
             }
             else if ((p = wtail) == null) { // initialize queue
                 WNode hd = new WNode(WMODE, null);
-                if (U.compareAndSwapObject(this, WHEAD, null, hd))
+                if (WHEAD.weakCompareAndSetVolatile(this, null, hd))
                     wtail = hd;
             }
             else if (node == null)
                 node = new WNode(WMODE, p);
             else if (node.prev != p)
                 node.prev = p;
-            else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
+            else if (WTAIL.weakCompareAndSetVolatile(this, p, node)) {
                 p.next = node;
                 break;
             }
@@ -1067,11 +1103,10 @@
                     spins = HEAD_SPINS;
                 else if (spins < MAX_HEAD_SPINS)
                     spins <<= 1;
-                for (int k = spins;;) { // spin at head
+                for (int k = spins; k > 0; --k) { // spin at head
                     long s, ns;
                     if (((s = state) & ABITS) == 0L) {
-                        if (U.compareAndSwapLong(this, STATE, s,
-                                                 ns = s + WBIT)) {
+                        if ((ns = tryWriteLock(s)) != 0L) {
                             whead = node;
                             node.prev = null;
                             if (wasInterrupted)
@@ -1079,17 +1114,16 @@
                             return ns;
                         }
                     }
-                    else if (LockSupport.nextSecondarySeed() >= 0 &&
-                             --k <= 0)
-                        break;
+                    else
+                        Thread.onSpinWait();
                 }
             }
             else if (h != null) { // help release stale waiters
                 WNode c; Thread w;
                 while ((c = h.cowait) != null) {
-                    if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                    if (WCOWAIT.weakCompareAndSetVolatile(h, c, c.cowait) &&
                         (w = c.thread) != null)
-                        U.unpark(w);
+                        LockSupport.unpark(w);
                 }
             }
             if (whead == h) {
@@ -1098,7 +1132,7 @@
                         (p = np).next = node;   // stale
                 }
                 else if ((ps = p.status) == 0)
-                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
+                    WSTATUS.compareAndSet(p, 0, WAITING);
                 else if (ps == CANCELLED) {
                     if ((pp = p.prev) != null) {
                         node.prev = pp;
@@ -1112,13 +1146,15 @@
                     else if ((time = deadline - System.nanoTime()) <= 0L)
                         return cancelWaiter(node, node, false);
                     Thread wt = Thread.currentThread();
-                    U.putObject(wt, PARKBLOCKER, this);
                     node.thread = wt;
                     if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
-                        whead == h && node.prev == p)
-                        U.park(false, time);  // emulate LockSupport.park
+                        whead == h && node.prev == p) {
+                        if (time == 0L)
+                            LockSupport.park(this);
+                        else
+                            LockSupport.parkNanos(this, time);
+                    }
                     node.thread = null;
-                    U.putObject(wt, PARKBLOCKER, null);
                     if (Thread.interrupted()) {
                         if (interruptible)
                             return cancelWaiter(node, node, true);
@@ -1146,7 +1182,7 @@
             if ((h = whead) == (p = wtail)) {
                 for (long m, s, ns;;) {
                     if ((m = (s = state) & ABITS) < RFULL ?
-                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
+                        casState(s, ns = s + RUNIT) :
                         (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
                         if (wasInterrupted)
                             Thread.currentThread().interrupt();
@@ -1154,8 +1190,8 @@
                     }
                     else if (m >= WBIT) {
                         if (spins > 0) {
-                            if (LockSupport.nextSecondarySeed() >= 0)
-                                --spins;
+                            --spins;
+                            Thread.onSpinWait();
                         }
                         else {
                             if (spins == 0) {
@@ -1170,7 +1206,7 @@
             }
             if (p == null) { // initialize queue
                 WNode hd = new WNode(WMODE, null);
-                if (U.compareAndSwapObject(this, WHEAD, null, hd))
+                if (WHEAD.weakCompareAndSetVolatile(this, null, hd))
                     wtail = hd;
             }
             else if (node == null)
@@ -1178,27 +1214,25 @@
             else if (h == p || p.mode != RMODE) {
                 if (node.prev != p)
                     node.prev = p;
-                else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
+                else if (WTAIL.weakCompareAndSetVolatile(this, p, node)) {
                     p.next = node;
                     break;
                 }
             }
-            else if (!U.compareAndSwapObject(p, WCOWAIT,
-                                             node.cowait = p.cowait, node))
+            else if (!WCOWAIT.compareAndSet(p, node.cowait = p.cowait, node))
                 node.cowait = null;
             else {
                 for (;;) {
                     WNode pp, c; Thread w;
                     if ((h = whead) != null && (c = h.cowait) != null &&
-                        U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                        WCOWAIT.compareAndSet(h, c, c.cowait) &&
                         (w = c.thread) != null) // help release
-                        U.unpark(w);
+                        LockSupport.unpark(w);
                     if (h == (pp = p.prev) || h == p || pp == null) {
                         long m, s, ns;
                         do {
                             if ((m = (s = state) & ABITS) < RFULL ?
-                                U.compareAndSwapLong(this, STATE, s,
-                                                     ns = s + RUNIT) :
+                                casState(s, ns = s + RUNIT) :
                                 (m < WBIT &&
                                  (ns = tryIncReaderOverflow(s)) != 0L)) {
                                 if (wasInterrupted)
@@ -1221,13 +1255,15 @@
                             return cancelWaiter(node, p, false);
                         }
                         Thread wt = Thread.currentThread();
-                        U.putObject(wt, PARKBLOCKER, this);
                         node.thread = wt;
                         if ((h != pp || (state & ABITS) == WBIT) &&
-                            whead == h && p.prev == pp)
-                            U.park(false, time);
+                            whead == h && p.prev == pp) {
+                            if (time == 0L)
+                                LockSupport.park(this);
+                            else
+                                LockSupport.parkNanos(this, time);
+                        }
                         node.thread = null;
-                        U.putObject(wt, PARKBLOCKER, null);
                         if (Thread.interrupted()) {
                             if (interruptible)
                                 return cancelWaiter(node, p, true);
@@ -1248,32 +1284,32 @@
                 for (int k = spins;;) { // spin at head
                     long m, s, ns;
                     if ((m = (s = state) & ABITS) < RFULL ?
-                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
+                        casState(s, ns = s + RUNIT) :
                         (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
                         WNode c; Thread w;
                         whead = node;
                         node.prev = null;
                         while ((c = node.cowait) != null) {
-                            if (U.compareAndSwapObject(node, WCOWAIT,
-                                                       c, c.cowait) &&
+                            if (WCOWAIT.compareAndSet(node, c, c.cowait) &&
                                 (w = c.thread) != null)
-                                U.unpark(w);
+                                LockSupport.unpark(w);
                         }
                         if (wasInterrupted)
                             Thread.currentThread().interrupt();
                         return ns;
                     }
-                    else if (m >= WBIT &&
-                             LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
+                    else if (m >= WBIT && --k <= 0)
                         break;
+                    else
+                        Thread.onSpinWait();
                 }
             }
             else if (h != null) {
                 WNode c; Thread w;
                 while ((c = h.cowait) != null) {
-                    if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                    if (WCOWAIT.compareAndSet(h, c, c.cowait) &&
                         (w = c.thread) != null)
-                        U.unpark(w);
+                        LockSupport.unpark(w);
                 }
             }
             if (whead == h) {
@@ -1282,7 +1318,7 @@
                         (p = np).next = node;   // stale
                 }
                 else if ((ps = p.status) == 0)
-                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
+                    WSTATUS.compareAndSet(p, 0, WAITING);
                 else if (ps == CANCELLED) {
                     if ((pp = p.prev) != null) {
                         node.prev = pp;
@@ -1296,14 +1332,16 @@
                     else if ((time = deadline - System.nanoTime()) <= 0L)
                         return cancelWaiter(node, node, false);
                     Thread wt = Thread.currentThread();
-                    U.putObject(wt, PARKBLOCKER, this);
                     node.thread = wt;
                     if (p.status < 0 &&
                         (p != h || (state & ABITS) == WBIT) &&
-                        whead == h && node.prev == p)
-                        U.park(false, time);
+                        whead == h && node.prev == p) {
+                            if (time == 0L)
+                                LockSupport.park(this);
+                            else
+                                LockSupport.parkNanos(this, time);
+                    }
                     node.thread = null;
-                    U.putObject(wt, PARKBLOCKER, null);
                     if (Thread.interrupted()) {
                         if (interruptible)
                             return cancelWaiter(node, node, true);
@@ -1325,7 +1363,7 @@
      * AbstractQueuedSynchronizer (see its detailed explanation in AQS
      * internal documentation).
      *
-     * @param node if nonnull, the waiter
+     * @param node if non-null, the waiter
      * @param group either node or the group node is cowaiting with
      * @param interrupted if already interrupted
      * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
@@ -1337,7 +1375,7 @@
             // unsplice cancelled nodes from group
             for (WNode p = group, q; (q = p.cowait) != null;) {
                 if (q.status == CANCELLED) {
-                    U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
+                    WCOWAIT.compareAndSet(p, q, q.cowait);
                     p = group; // restart
                 }
                 else
@@ -1346,7 +1384,7 @@
             if (group == node) {
                 for (WNode r = group.cowait; r != null; r = r.cowait) {
                     if ((w = r.thread) != null)
-                        U.unpark(w);       // wake up uncancelled co-waiters
+                        LockSupport.unpark(w); // wake up uncancelled co-waiters
                 }
                 for (WNode pred = node.prev; pred != null; ) { // unsplice
                     WNode succ, pp;        // find valid successor
@@ -1357,23 +1395,23 @@
                             if (t.status != CANCELLED)
                                 q = t;     // don't link if succ cancelled
                         if (succ == q ||   // ensure accurate successor
-                            U.compareAndSwapObject(node, WNEXT,
-                                                   succ, succ = q)) {
+                            WNEXT.compareAndSet(node, succ, succ = q)) {
                             if (succ == null && node == wtail)
-                                U.compareAndSwapObject(this, WTAIL, node, pred);
+                                WTAIL.compareAndSet(this, node, pred);
                             break;
                         }
                     }
                     if (pred.next == node) // unsplice pred link
-                        U.compareAndSwapObject(pred, WNEXT, node, succ);
+                        WNEXT.compareAndSet(pred, node, succ);
                     if (succ != null && (w = succ.thread) != null) {
+                        // wake up succ to observe new pred
                         succ.thread = null;
-                        U.unpark(w);       // wake up succ to observe new pred
+                        LockSupport.unpark(w);
                     }
                     if (pred.status != CANCELLED || (pp = pred.prev) == null)
                         break;
                     node.prev = pp;        // repeat if new pred wrong/cancelled
-                    U.compareAndSwapObject(pp, WNEXT, pred, succ);
+                    WNEXT.compareAndSet(pp, pred, succ);
                     pred = pp;
                 }
             }
@@ -1397,34 +1435,22 @@
         return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
     }
 
-    // Unsafe mechanics
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long STATE;
-    private static final long WHEAD;
-    private static final long WTAIL;
-    private static final long WNEXT;
-    private static final long WSTATUS;
-    private static final long WCOWAIT;
-    private static final long PARKBLOCKER;
-
+    // VarHandle mechanics
+    private static final VarHandle STATE;
+    private static final VarHandle WHEAD;
+    private static final VarHandle WTAIL;
+    private static final VarHandle WNEXT;
+    private static final VarHandle WSTATUS;
+    private static final VarHandle WCOWAIT;
     static {
         try {
-            STATE = U.objectFieldOffset
-                (StampedLock.class.getDeclaredField("state"));
-            WHEAD = U.objectFieldOffset
-                (StampedLock.class.getDeclaredField("whead"));
-            WTAIL = U.objectFieldOffset
-                (StampedLock.class.getDeclaredField("wtail"));
-
-            WSTATUS = U.objectFieldOffset
-                (WNode.class.getDeclaredField("status"));
-            WNEXT = U.objectFieldOffset
-                (WNode.class.getDeclaredField("next"));
-            WCOWAIT = U.objectFieldOffset
-                (WNode.class.getDeclaredField("cowait"));
-
-            PARKBLOCKER = U.objectFieldOffset
-                (Thread.class.getDeclaredField("parkBlocker"));
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(StampedLock.class, "state", long.class);
+            WHEAD = l.findVarHandle(StampedLock.class, "whead", WNode.class);
+            WTAIL = l.findVarHandle(StampedLock.class, "wtail", WNode.class);
+            WSTATUS = l.findVarHandle(WNode.class, "status", int.class);
+            WNEXT = l.findVarHandle(WNode.class, "next", WNode.class);
+            WCOWAIT = l.findVarHandle(WNode.class, "cowait", WNode.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java	Wed Jul 05 22:00:06 2017 +0200
@@ -262,7 +262,6 @@
  *
  * </ul>
  *
- *
  * The methods of all classes in {@code java.util.concurrent} and its
  * subpackages extend these guarantees to higher-level
  * synchronization.  In particular:
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Wed Jul 05 22:00:06 2017 +0200
@@ -141,7 +141,6 @@
     private boolean verify;
     private final Runtime.Version version;  // current version
     private final int versionMajor;         // version.major()
-    private boolean notVersioned;           // legacy constructor called
     private boolean isMultiRelease;         // is jar multi-release?
 
     // indicates if Class-Path attribute present
@@ -290,7 +289,6 @@
      */
     public JarFile(File file, boolean verify, int mode) throws IOException {
         this(file, verify, mode, BASE_VERSION);
-        this.notVersioned = true;
     }
 
     /**
@@ -496,42 +494,14 @@
             Iterator<JarEntry>
     {
         final Enumeration<? extends ZipEntry> e = JarFile.super.entries();
-        ZipEntry ze;
 
         public boolean hasNext() {
-            if (notVersioned) {
-                return e.hasMoreElements();
-            }
-            if (ze != null) {
-                return true;
-            }
-            return findNext();
-        }
-
-        private boolean findNext() {
-            while (e.hasMoreElements()) {
-                ZipEntry ze2 = e.nextElement();
-                if (!ze2.getName().startsWith(META_INF_VERSIONS)) {
-                    ze = ze2;
-                    return true;
-                }
-            }
-            return false;
+            return e.hasMoreElements();
         }
 
         public JarEntry next() {
-            ZipEntry ze2;
-
-            if (notVersioned) {
-                ze2 = e.nextElement();
-                return new JarFileEntry(ze2.getName(), ze2);
-            }
-            if (ze != null || findNext()) {
-                ze2 = ze;
-                ze = null;
-                return new JarFileEntry(ze2);
-            }
-            throw new NoSuchElementException();
+            ZipEntry ze = e.nextElement();
+            return new JarFileEntry(ze.getName(), ze);
         }
 
         public boolean hasMoreElements() {
@@ -548,19 +518,7 @@
     }
 
     /**
-     * Returns an enumeration of the jar file entries.  The set of entries
-     * returned depends on whether or not the jar file is a multi-release jar
-     * file, and on the constructor used to create the {@code JarFile}.  If the
-     * jar file is not a multi-release jar file, all entries are returned,
-     * regardless of how the {@code JarFile} is created.  If the constructor
-     * does not take a {@code Release} argument, all entries are returned.
-     * If the jar file is a multi-release jar file and the constructor takes a
-     * {@code Release} argument, then the set of entries returned is equivalent
-     * to the set of entries that would be returned if the set was built by
-     * invoking {@link JarFile#getEntry(String)} or
-     * {@link JarFile#getJarEntry(String)} with the name of each base entry in
-     * the jar file.  A base entry is an entry whose path name does not start
-     * with "META-INF/versions/".
+     * Returns an enumeration of the jar file entries.
      *
      * @return an enumeration of the jar file entries
      * @throws IllegalStateException
@@ -571,24 +529,26 @@
     }
 
     /**
-     * Returns an ordered {@code Stream} over all the jar file entries.
+     * Returns an ordered {@code Stream} over the jar file entries.
      * Entries appear in the {@code Stream} in the order they appear in
-     * the central directory of the jar file.  The set of entries
-     * returned depends on whether or not the jar file is a multi-release jar
-     * file, and on the constructor used to create the {@code JarFile}.  If the
-     * jar file is not a multi-release jar file, all entries are returned,
-     * regardless of how the {@code JarFile} is created.  If the constructor
-     * does not take a {@code Release} argument, all entries are returned.
-     * If the jar file is a multi-release jar file and the constructor takes a
-     * {@code Release} argument, then the set of entries returned is equivalent
-     * to the set of entries that would be returned if the set was built by
-     * invoking {@link JarFile#getEntry(String)} or
-     * {@link JarFile#getJarEntry(String)} with the name of each base entry in
-     * the jar file.  A base entry is an entry whose path name does not start
-     * with "META-INF/versions/".
+     * the central directory of the jar file.
+     *
      * @return an ordered {@code Stream} of entries in this jar file
      * @throws IllegalStateException if the jar file has been closed
      * @since 1.8
+     *
+     * @apiNote  A versioned view of the stream obtained from a {@code JarFile}
+     * configured to process a multi-release jar file can be created with code
+     * similar to the following:
+     * <pre>
+     * {@code
+     *     Stream<JarEntry> versionedStream(JarFile jf) {
+     *         return jf.stream().map(JarEntry::getName)
+     *                  .filter(name -> !name.startsWith("META-INF/versions/"))
+     *                  .map(jf::getJarEntry);
+     *     }
+     * }
+     * </pre>
      */
     public Stream<JarEntry> stream() {
         return StreamSupport.stream(Spliterators.spliterator(
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipEntry.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipEntry.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -568,9 +568,18 @@
                     int pos = off + 4;               // reserved 4 bytes
                     if (get16(extra, pos) !=  0x0001 || get16(extra, pos + 2) != 24)
                         break;
-                    mtime = winTimeToFileTime(get64(extra, pos + 4));
-                    atime = winTimeToFileTime(get64(extra, pos + 12));
-                    ctime = winTimeToFileTime(get64(extra, pos + 20));
+                    long wtime = get64(extra, pos + 4);
+                    if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+                        mtime = winTimeToFileTime(wtime);
+                    }
+                    wtime = get64(extra, pos + 12);
+                    if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+                        atime = winTimeToFileTime(wtime);
+                    }
+                    wtime = get64(extra, pos + 20);
+                    if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+                        ctime = winTimeToFileTime(wtime);
+                    }
                     break;
                 case EXTID_EXTT:
                     int flag = Byte.toUnsignedInt(extra[off]);
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -421,22 +421,36 @@
         byte[] nameBytes = zc.getBytes(e.name);
         writeShort(nameBytes.length);
 
-        int elenEXTT = 0;               // info-zip extended timestamp
+        int elenEXTT = 0;         // info-zip extended timestamp
         int flagEXTT = 0;
+        long umtime = -1;
+        long uatime = -1;
+        long uctime = -1;
         if (e.mtime != null) {
             elenEXTT += 4;
             flagEXTT |= EXTT_FLAG_LMT;
+            umtime = fileTimeToUnixTime(e.mtime);
         }
         if (e.atime != null) {
             elenEXTT += 4;
             flagEXTT |= EXTT_FLAG_LAT;
+            uatime = fileTimeToUnixTime(e.atime);
         }
         if (e.ctime != null) {
             elenEXTT += 4;
             flagEXTT |= EXTT_FLAT_CT;
+            uctime = fileTimeToUnixTime(e.ctime);
         }
-        if (flagEXTT != 0)
-            elen += (elenEXTT + 5);    // headid(2) + size(2) + flag(1) + data
+        if (flagEXTT != 0) {
+            // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
+            if (umtime > UPPER_UNIXTIME_BOUND ||
+                uatime > UPPER_UNIXTIME_BOUND ||
+                uctime > UPPER_UNIXTIME_BOUND) {
+                elen += 36;                // NTFS time, total 36 bytes
+            } else {
+                elen += (elenEXTT + 5);    // headid(2) + size(2) + flag(1) + data
+            }
+        }
         writeShort(elen);
         writeBytes(nameBytes, 0, nameBytes.length);
         if (hasZip64) {
@@ -446,15 +460,31 @@
             writeLong(e.csize);
         }
         if (flagEXTT != 0) {
-            writeShort(EXTID_EXTT);
-            writeShort(elenEXTT + 1);      // flag + data
-            writeByte(flagEXTT);
-            if (e.mtime != null)
-                writeInt(fileTimeToUnixTime(e.mtime));
-            if (e.atime != null)
-                writeInt(fileTimeToUnixTime(e.atime));
-            if (e.ctime != null)
-                writeInt(fileTimeToUnixTime(e.ctime));
+            if (umtime > UPPER_UNIXTIME_BOUND ||
+                uatime > UPPER_UNIXTIME_BOUND ||
+                uctime > UPPER_UNIXTIME_BOUND) {
+                writeShort(EXTID_NTFS);    // id
+                writeShort(32);            // data size
+                writeInt(0);               // reserved
+                writeShort(0x0001);        // NTFS attr tag
+                writeShort(24);
+                writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.mtime));
+                writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.atime));
+                writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.ctime));
+            } else {
+                writeShort(EXTID_EXTT);
+                writeShort(elenEXTT + 1);  // flag + data
+                writeByte(flagEXTT);
+                if (e.mtime != null)
+                    writeInt(umtime);
+                if (e.atime != null)
+                    writeInt(uatime);
+                if (e.ctime != null)
+                    writeInt(uctime);
+            }
         }
         writeExtra(e.extra);
         locoff = written;
@@ -528,18 +558,30 @@
         // cen info-zip extended timestamp only outputs mtime
         // but set the flag for a/ctime, if present in loc
         int flagEXTT = 0;
+        long umtime = -1;
+        long uatime = -1;
+        long uctime = -1;
         if (e.mtime != null) {
-            elen += 4;              // + mtime(4)
             flagEXTT |= EXTT_FLAG_LMT;
+            umtime = fileTimeToUnixTime(e.mtime);
         }
         if (e.atime != null) {
             flagEXTT |= EXTT_FLAG_LAT;
+            uatime = fileTimeToUnixTime(e.atime);
         }
         if (e.ctime != null) {
             flagEXTT |= EXTT_FLAT_CT;
+            uctime = fileTimeToUnixTime(e.ctime);
         }
         if (flagEXTT != 0) {
-            elen += 5;             // headid + sz + flag
+            // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
+            if (umtime > UPPER_UNIXTIME_BOUND ||
+                uatime > UPPER_UNIXTIME_BOUND ||
+                uctime > UPPER_UNIXTIME_BOUND) {
+                elen += 36;         // NTFS time total 36 bytes
+            } else {
+                elen += 9;          // headid(2) + sz(2) + flag(1) + mtime (4)
+            }
         }
         writeShort(elen);
         byte[] commentBytes;
@@ -568,14 +610,30 @@
                 writeLong(xentry.offset);
         }
         if (flagEXTT != 0) {
-            writeShort(EXTID_EXTT);
-            if (e.mtime != null) {
-                writeShort(5);      // flag + mtime
-                writeByte(flagEXTT);
-                writeInt(fileTimeToUnixTime(e.mtime));
+            if (umtime > UPPER_UNIXTIME_BOUND ||
+                uatime > UPPER_UNIXTIME_BOUND ||
+                uctime > UPPER_UNIXTIME_BOUND) {
+                writeShort(EXTID_NTFS);    // id
+                writeShort(32);            // data size
+                writeInt(0);               // reserved
+                writeShort(0x0001);        // NTFS attr tag
+                writeShort(24);
+                writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.mtime));
+                writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.atime));
+                writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.ctime));
             } else {
-                writeShort(1);      // flag only
-                writeByte(flagEXTT);
+                writeShort(EXTID_EXTT);
+                if (e.mtime != null) {
+                    writeShort(5);      // flag + mtime
+                    writeByte(flagEXTT);
+                    writeInt(umtime);
+                } else {
+                    writeShort(1);      // flag only
+                    writeByte(flagEXTT);
+                }
             }
         }
         writeExtra(e.extra);
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipUtils.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipUtils.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,9 @@
     // used to adjust values between Windows and java epoch
     private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
 
+    // used to indicate the corresponding windows time is not available
+    public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
+
     /**
      * Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
      */
@@ -54,6 +57,11 @@
     }
 
     /**
+     * The upper bound of the 32-bit unix time, the "year 2038 problem".
+     */
+    public static final long UPPER_UNIXTIME_BOUND = 0x7fffffff;
+
+    /**
      * Converts "standard Unix time"(in seconds, UTC/GMT) to FileTime
      */
     public static final FileTime unixTimeToFileTime(long utime) {
--- a/jdk/src/java.base/share/classes/javax/security/auth/SubjectDomainCombiner.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/security/auth/SubjectDomainCombiner.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -110,16 +110,18 @@
      * {@code SubjectDomainCombiner}.
      *
      * <p> A new {@code ProtectionDomain} instance is created
-     * for each {@code ProtectionDomain} in the
-     * {@code currentDomains} array.  Each new {@code ProtectionDomain}
+     * for each non-static {@code ProtectionDomain} (
+     * (staticPermissionsOnly() == false)
+     * in the {@code currentDomains} array.  Each new {@code ProtectionDomain}
      * instance is created using the {@code CodeSource},
      * {@code Permission}s and {@code ClassLoader}
      * from the corresponding {@code ProtectionDomain} in
      * {@code currentDomains}, as well as with the Principals from
      * the {@code Subject} associated with this
-     * {@code SubjectDomainCombiner}.
+     * {@code SubjectDomainCombiner}. Static ProtectionDomains are
+     * combined as-is and no new instance is created.
      *
-     * <p> All of the newly instantiated ProtectionDomains are
+     * <p> All of the ProtectionDomains (static and newly instantiated) are
      * combined into a new array.  The ProtectionDomains from the
      * {@code assignedDomains} array are appended to this new array,
      * and the result is returned.
@@ -233,10 +235,15 @@
                 subjectPd = cachedPDs.getValue(pd);
 
                 if (subjectPd == null) {
-                    subjectPd = new ProtectionDomain(pd.getCodeSource(),
+                    if (pd.staticPermissionsOnly()) {
+                        // keep static ProtectionDomain objects static
+                        subjectPd = pd;
+                    } else {
+                        subjectPd = new ProtectionDomain(pd.getCodeSource(),
                                                 pd.getPermissions(),
                                                 pd.getClassLoader(),
                                                 principals);
+                    }
                     cachedPDs.putValue(pd, subjectPd);
                 } else {
                     allNew = false;
@@ -335,60 +342,62 @@
                 ProtectionDomain subjectPd = cachedPDs.getValue(pd);
 
                 if (subjectPd == null) {
-
-                    // XXX
-                    // we must first add the original permissions.
-                    // that way when we later add the new JAAS permissions,
-                    // any unresolved JAAS-related permissions will
-                    // automatically get resolved.
+                    if (pd.staticPermissionsOnly()) {
+                        // keep static ProtectionDomain objects static
+                        subjectPd = pd;
+                    } else {
+                        // XXX
+                        // we must first add the original permissions.
+                        // that way when we later add the new JAAS permissions,
+                        // any unresolved JAAS-related permissions will
+                        // automatically get resolved.
 
-                    // get the original perms
-                    Permissions perms = new Permissions();
-                    PermissionCollection coll = pd.getPermissions();
-                    java.util.Enumeration<Permission> e;
-                    if (coll != null) {
-                        synchronized (coll) {
-                            e = coll.elements();
-                            while (e.hasMoreElements()) {
-                                Permission newPerm =
+                        // get the original perms
+                        Permissions perms = new Permissions();
+                        PermissionCollection coll = pd.getPermissions();
+                        java.util.Enumeration<Permission> e;
+                        if (coll != null) {
+                            synchronized (coll) {
+                                e = coll.elements();
+                                while (e.hasMoreElements()) {
+                                    Permission newPerm =
                                         e.nextElement();
-                                 perms.add(newPerm);
+                                    perms.add(newPerm);
+                                }
                             }
                         }
-                    }
-
-                    // get perms from the policy
 
-                    final java.security.CodeSource finalCs = pd.getCodeSource();
-                    final Subject finalS = subject;
-                    PermissionCollection newPerms =
-                        java.security.AccessController.doPrivileged
-                        (new PrivilegedAction<PermissionCollection>() {
-                        @SuppressWarnings("deprecation")
-                        public PermissionCollection run() {
-                          return
-                          javax.security.auth.Policy.getPolicy().getPermissions
-                                (finalS, finalCs);
-                        }
-                    });
+                        // get perms from the policy
+                        final java.security.CodeSource finalCs = pd.getCodeSource();
+                        final Subject finalS = subject;
+                        PermissionCollection newPerms =
+                            java.security.AccessController.doPrivileged
+                            (new PrivilegedAction<PermissionCollection>() {
+                            @SuppressWarnings("deprecation")
+                            public PermissionCollection run() {
+                                return
+                                    javax.security.auth.Policy.getPolicy().getPermissions
+                                    (finalS, finalCs);
+                            }
+                        });
 
-                    // add the newly granted perms,
-                    // avoiding duplicates
-                    synchronized (newPerms) {
-                        e = newPerms.elements();
-                        while (e.hasMoreElements()) {
-                            Permission newPerm = e.nextElement();
-                            if (!perms.implies(newPerm)) {
-                                perms.add(newPerm);
-                                if (debug != null)
-                                    debug.println (
-                                        "Adding perm " + newPerm + "\n");
+                        // add the newly granted perms,
+                        // avoiding duplicates
+                        synchronized (newPerms) {
+                            e = newPerms.elements();
+                            while (e.hasMoreElements()) {
+                                Permission newPerm = e.nextElement();
+                                if (!perms.implies(newPerm)) {
+                                    perms.add(newPerm);
+                                    if (debug != null)
+                                        debug.println (
+                                            "Adding perm " + newPerm + "\n");
+                                }
                             }
                         }
+                        subjectPd = new ProtectionDomain
+                            (finalCs, perms, pd.getClassLoader(), principals);
                     }
-                    subjectPd = new ProtectionDomain
-                        (finalCs, perms, pd.getClassLoader(), principals);
-
                     if (allowCaching)
                         cachedPDs.putValue(pd, subjectPd);
                 }
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java	Wed Jul 05 22:00:06 2017 +0200
@@ -21,7 +21,7 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
-*/
+ */
 
 package jdk.internal.jimage;
 
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,18 +3,18 @@
  * 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 License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General License
+ * 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 License version
+ * 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.
  *
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Wed Jul 05 22:00:06 2017 +0200
@@ -26,8 +26,6 @@
 package jdk.internal.misc;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
-import jdk.internal.reflect.CallerSensitive;
-import jdk.internal.reflect.Reflection;
 import jdk.internal.vm.annotation.ForceInline;
 
 import java.lang.reflect.Field;
@@ -57,7 +55,6 @@
     private static native void registerNatives();
     static {
         registerNatives();
-        Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
     }
 
     private Unsafe() {}
@@ -87,16 +84,8 @@
      * }}</pre>
      *
      * (It may assist compilers to make the local variable {@code final}.)
-     *
-     * @throws  SecurityException if the class loader of the caller
-     *          class is not in the system domain in which all permissions
-     *          are granted.
      */
-    @CallerSensitive
     public static Unsafe getUnsafe() {
-        Class<?> caller = Reflection.getCallerClass();
-        if (!VM.isSystemDomainLoader(caller.getClassLoader()))
-            throw new SecurityException("Unsafe");
         return theUnsafe;
     }
 
--- a/jdk/src/java.base/share/classes/jdk/internal/ref/WeakCleanable.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/jdk/internal/ref/WeakCleanable.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,3 @@
-package jdk.internal.ref;
-
 /*
  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -25,6 +23,8 @@
  * questions.
  */
 
+package jdk.internal.ref;
+
 import java.lang.ref.Cleaner;
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
--- a/jdk/src/java.base/share/classes/module-info.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/module-info.java	Wed Jul 05 22:00:06 2017 +0200
@@ -149,7 +149,6 @@
     exports jdk.internal.module to
         java.instrument,
         java.management,
-        java.xml,
         jdk.dynalink,
         jdk.jartool,
         jdk.jlink;
@@ -282,15 +281,18 @@
         jdk.security.auth;
     exports sun.text.resources to
         jdk.localedata;
-    exports sun.util.resources to
-        jdk.localedata;
+    exports sun.util.cldr to
+        jdk.jlink;
     exports sun.util.locale.provider to
         java.desktop,
+        jdk.jlink,
         jdk.localedata;
     exports sun.util.logging to
         java.desktop,
         java.logging,
         java.prefs;
+    exports sun.util.resources to
+        jdk.localedata;
 
     // JDK-internal service types
     uses jdk.internal.logger.DefaultLoggerFinder;
@@ -306,4 +308,3 @@
     provides java.nio.file.spi.FileSystemProvider with
         jdk.internal.jrtfs.JrtFileSystemProvider;
 }
-
--- a/jdk/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1707,7 +1707,7 @@
      */
     public InputStream nameList(String path) throws sun.net.ftp.FtpProtocolException, IOException {
         Socket s;
-        s = openDataConnection("NLST " + path);
+        s = openDataConnection(path == null ? "NLST" : "NLST " + path);
         if (s != null) {
             return createInputStream(s.getInputStream());
         }
--- a/jdk/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/GenericArrayTypeImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/GenericArrayTypeImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -65,15 +65,7 @@
     }
 
     public String toString() {
-        Type componentType = getGenericComponentType();
-        StringBuilder sb = new StringBuilder();
-
-        if (componentType instanceof Class)
-            sb.append(((Class)componentType).getName() );
-        else
-            sb.append(componentType.toString());
-        sb.append("[]");
-        return sb.toString();
+        return getGenericComponentType().getTypeName() + "[]";
     }
 
     @Override
--- a/jdk/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.util.Arrays;
+import java.util.StringJoiner;
 import java.util.Objects;
 
 /** Implementing class for ParameterizedType interface. */
@@ -207,12 +208,9 @@
         StringBuilder sb = new StringBuilder();
 
         if (ownerType != null) {
-            if (ownerType instanceof Class)
-                sb.append(((Class)ownerType).getName());
-            else
-                sb.append(ownerType.toString());
+            sb.append(ownerType.getTypeName());
 
-            sb.append(".");
+            sb.append("$");
 
             if (ownerType instanceof ParameterizedTypeImpl) {
                 // Find simple name of nested type by removing the
@@ -220,21 +218,17 @@
                 sb.append(rawType.getName().replace( ((ParameterizedTypeImpl)ownerType).rawType.getName() + "$",
                                          ""));
             } else
-                sb.append(rawType.getName());
+               sb.append(rawType.getSimpleName());
         } else
             sb.append(rawType.getName());
 
-        if (actualTypeArguments != null &&
-            actualTypeArguments.length > 0) {
-            sb.append("<");
-            boolean first = true;
+        if (actualTypeArguments != null) {
+            StringJoiner sj = new StringJoiner(", ", "<", ">");
+            sj.setEmptyValue("");
             for(Type t: actualTypeArguments) {
-                if (!first)
-                    sb.append(", ");
-                sb.append(t.getTypeName());
-                first = false;
+                sj.add(t.getTypeName());
             }
-            sb.append(">");
+            sb.append(sj.toString());
         }
 
         return sb.toString();
--- a/jdk/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/WildcardTypeImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/WildcardTypeImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import sun.reflect.generics.tree.FieldTypeSignature;
 import sun.reflect.generics.visitor.Reifier;
 import java.util.Arrays;
+import java.util.StringJoiner;
 
 
 /**
@@ -156,14 +157,12 @@
 
         assert bounds.length > 0;
 
-        boolean first = true;
+        StringJoiner sj = new StringJoiner(" & ");
         for(Type bound: bounds) {
-            if (!first)
-                sb.append(" & ");
+            sj.add(bound.getTypeName());
+        }
+        sb.append(sj.toString());
 
-            first = false;
-            sb.append(bound.getTypeName());
-        }
         return sb.toString();
     }
 
--- a/jdk/src/java.base/share/classes/sun/security/provider/DSA.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/provider/DSA.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -329,6 +329,10 @@
                 r = values[0].getBigInteger();
                 s = values[1].getBigInteger();
 
+                // Check for trailing signature data
+                if (in.available() != 0) {
+                    throw new IOException("Incorrect signature length");
+                }
             } catch (IOException e) {
                 throw new SignatureException("invalid encoding for signature");
             }
--- a/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/jdk/src/java.base/share/conf/security/java.security	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/conf/security/java.security	Wed Jul 05 22:00:06 2017 +0200
@@ -652,8 +652,8 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024, EC keySize < 224
+jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & denyAfter 2017-01-01, \
+    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS/DTLS) processing
--- a/jdk/src/java.base/share/native/include/jvmti.h	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/include/jvmti.h	Wed Jul 05 22:00:06 2017 +0200
@@ -1217,8 +1217,11 @@
     jmethodID method,
     jlocation location);
 
-  /*   40 :  RESERVED */
-  void *reserved40;
+  /*   40 : Get Named Module */
+  jvmtiError (JNICALL *GetNamedModule) (jvmtiEnv* env,
+    jobject class_loader,
+    const char* package_name,
+    jobject* module_ptr);
 
   /*   41 : Set Field Access Watch */
   jvmtiError (JNICALL *SetFieldAccessWatch) (jvmtiEnv* env,
@@ -2146,6 +2149,12 @@
     return functions->GetAllModules(this, module_count_ptr, modules_ptr);
   }
 
+  jvmtiError GetNamedModule(jobject class_loader,
+            const char* package_name,
+            jobject* module_ptr) {
+    return functions->GetNamedModule(this, class_loader, package_name, module_ptr);
+  }
+
   jvmtiError GetLoadedClasses(jint* class_count_ptr,
             jclass** classes_ptr) {
     return functions->GetLoadedClasses(this, class_count_ptr, classes_ptr);
--- a/jdk/src/java.base/share/native/libfdlibm/e_acos.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_acos.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_asin.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_asin.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_atan2.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_atan2.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_atanh.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_atanh.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_cosh.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_cosh.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_exp.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_exp.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_fmod.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_fmod.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_log.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_log.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_log10.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_log10.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_rem_pio2.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_rem_pio2.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_remainder.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_remainder.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_scalb.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_scalb.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/e_sinh.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/e_sinh.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/fdlibm.h	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/fdlibm.h	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/k_cos.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/k_cos.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/k_rem_pio2.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/k_rem_pio2.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/k_sin.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/k_sin.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/k_standard.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/k_standard.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/k_tan.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/k_tan.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_atan.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_atan.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_ceil.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_ceil.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_copysign.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_copysign.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_cos.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_cos.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_expm1.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_expm1.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_fabs.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_fabs.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_finite.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_finite.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_floor.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_floor.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_frexp.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_frexp.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_ilogb.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_ilogb.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_isnan.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_isnan.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_ldexp.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_ldexp.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_lib_version.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_lib_version.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_log1p.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_log1p.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_logb.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_logb.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_matherr.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_matherr.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_modf.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_modf.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_nextafter.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_nextafter.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_rint.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_rint.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_scalbn.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_scalbn.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_significand.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_significand.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_sin.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_sin.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_tan.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_tan.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libfdlibm/s_tanh.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libfdlibm/s_tanh.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.base/share/native/libjimage/NativeImageBuffer.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libjimage/NativeImageBuffer.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/src/java.base/share/native/libjimage/endian.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libjimage/endian.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/src/java.base/share/native/libjimage/imageFile.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libjimage/imageFile.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/src/java.base/share/native/libjimage/jimage.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/share/native/libjimage/jimage.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -85,7 +85,7 @@
  * Ex.
  *  const char* package = (*JImagePackageToModule)(image, "java/lang");
  *  tty->print_cr(package);
- *  —> java.base
+ *  -> java.base
  */
 extern "C" const char* JIMAGE_PackageToModule(JImageFile* image, const char* package_name) {
     return ((ImageFileReader*) image)->get_image_module_data()->package_to_module(package_name);
@@ -137,7 +137,7 @@
 }
 
 /*
- * JImageGetResource - Given an open image file (see JImageOpen), a resource’s
+ * JImageGetResource - Given an open image file (see JImageOpen), a resource's
  * location information (see JImageFindResource), a buffer of appropriate
  * size and the size, retrieve the bytes associated with the
  * resource. If the size is less than the resource size then the read is truncated.
@@ -168,7 +168,7 @@
  * Ex.
  *   bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version,
  *                  const char* package, const char* name, const char* extension, void* arg) {
- *     if (strcmp(extension, “class”) == 0) {
+ *     if (strcmp(extension, "class") == 0) {
  *       char path[JIMAGE_MAX_PATH];
  *       Thread* THREAD = Thread::current();
  *       jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name);
--- a/jdk/src/java.base/unix/classes/java/lang/ClassLoaderHelper.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/unix/classes/java/lang/ClassLoaderHelper.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.lang;
 
 import java.io.File;
--- a/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007,2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net;
 
 import sun.security.action.GetPropertyAction;
--- a/jdk/src/java.base/unix/native/libnet/NetworkInterface.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnet/NetworkInterface.c	Wed Jul 05 22:00:06 2017 +0200
@@ -25,9 +25,6 @@
 
 #include <errno.h>
 #include <strings.h>
-#if defined(_ALLBSD_SOURCE) && defined(__OpenBSD__)
-#include <sys/types.h>
-#endif
 #include <netinet/in.h>
 #include <stdlib.h>
 #include <string.h>
@@ -46,7 +43,6 @@
 
 #if defined(__linux__)
 #include <sys/ioctl.h>
-#include <bits/ioctls.h>
 #include <sys/utsname.h>
 #include <stdio.h>
 #endif
@@ -76,9 +72,23 @@
 #include "net_util.h"
 
 #if defined(__linux__)
-#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
+    #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
+#elif defined(__solaris__)
+    #ifndef SIOCGLIFHWADDR
+        #define SIOCGLIFHWADDR _IOWR('i', 192, struct lifreq)
+    #endif
+    #define DEV_PREFIX "/dev/"
 #endif
 
+#define CHECKED_MALLOC3(_pointer, _type, _size) \
+    do { \
+        _pointer = (_type)malloc(_size); \
+        if (_pointer == NULL) { \
+            JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
+            return ifs; /* return untouched list */ \
+        } \
+    } while(0)
+
 typedef struct _netaddr  {
     struct sockaddr *addr;
     struct sockaddr *brdcast;
@@ -130,40 +140,31 @@
 static netif  *enumInterfaces(JNIEnv *env);
 static netif  *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);
 
-#ifdef AF_INET6
+#if defined(AF_INET6)
 static netif  *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);
 #endif
 
 static netif  *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
-                     struct sockaddr *ifr_addrP, struct sockaddr *ifr_broadaddrP,
-                     struct sockaddr *ifr_subnetaddrP, int family, short prefix);
+                     struct sockaddr *ifr_addrP,
+                     struct sockaddr *ifr_broadaddrP,
+                     int family, short prefix);
 static void    freeif(netif *ifs);
 
 static int     openSocket(JNIEnv *env, int proto);
 static int     openSocketWithFallback(JNIEnv *env, const char *ifname);
 
+static short   translateIPv4AddressToPrefix(struct sockaddr_in *addr);
+static short   translateIPv6AddressToPrefix(struct sockaddr_in6 *addr);
 
-static struct  sockaddr *getBroadcast(JNIEnv *env, int sock, const char *name,
-                                      struct sockaddr *brdcast_store);
-static short   getSubnet(JNIEnv *env, int sock, const char *ifname);
-static short   computeMaskFromAddress(struct sockaddr *ifr_subnetaddrP);
 static int     getIndex(int sock, const char *ifname);
-
 static int     getFlags(int sock, const char *ifname, int *flags);
-static int     getMacAddress(JNIEnv *env, int sock,  const char *ifname,
+static int     getMacAddress(JNIEnv *env, int sock, const char *ifname,
                              const struct in_addr *addr, unsigned char *buf);
 static int     getMTU(JNIEnv *env, int sock, const char *ifname);
 
-
 #if defined(__solaris__)
-static netif  *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family);
 static int     getMacFromDevice(JNIEnv *env, const char *ifname,
                                 unsigned char *retbuf);
-
-#ifndef SIOCGLIFHWADDR
-#define SIOCGLIFHWADDR _IOWR('i', 192, struct lifreq)
-#endif
-
 #endif
 
 /******************* Java entry points *****************************/
@@ -259,7 +260,7 @@
     }
 
     // if found create a NetworkInterface
-    if (curr != NULL) {;
+    if (curr != NULL) {
         obj = createNetworkInterface(env, curr);
     }
 
@@ -299,7 +300,7 @@
     }
 
     // if found create a NetworkInterface
-    if (curr != NULL) {;
+    if (curr != NULL) {
         obj = createNetworkInterface(env, curr);
     }
 
@@ -317,7 +318,7 @@
 {
     netif *ifs, *curr;
 
-#ifdef AF_INET6
+#if defined(AF_INET6)
     int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6;
 #else
     int family =  AF_INET;
@@ -335,7 +336,7 @@
     while (curr != NULL) {
         netaddr *addrP = curr->addr;
 
-        // Iterate through each address on the interface
+        // iterate through each address on the interface
         while (addrP != NULL) {
 
             if (family == addrP->family) {
@@ -350,7 +351,7 @@
                     }
                 }
 
-#ifdef AF_INET6
+#if defined(AF_INET6)
                 if (family == AF_INET6) {
                     jbyte *bytes = (jbyte *)&(
                         ((struct sockaddr_in6*)addrP->addr)->sin6_addr);
@@ -385,7 +386,7 @@
     }
 
     // if found create a NetworkInterface
-    if (match) {;
+    if (match) {
         obj = createNetworkInterface(env, curr);
     }
 
@@ -634,7 +635,7 @@
  * populates the InetAddress array based on the IP addresses for this
  * interface.
  */
-jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
+static jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
     jobject netifObj;
     jobject name;
     jobjectArray addrArr;
@@ -712,7 +713,7 @@
             }
         }
 
-#ifdef AF_INET6
+#if defined(AF_INET6)
         if (addrP->family == AF_INET6) {
             int scope=0;
             iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
@@ -803,7 +804,7 @@
     // return partial list if an exception occurs in the middle of process ???
 
     // If IPv6 is available then enumerate IPv6 addresses.
-#ifdef AF_INET6
+#if defined(AF_INET6)
 
         // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
         // so we have to call ipv6_available()
@@ -829,20 +830,10 @@
     return ifs;
 }
 
-#define CHECKED_MALLOC3(_pointer, _type, _size) \
-    do { \
-        _pointer = (_type)malloc(_size); \
-        if (_pointer == NULL) { \
-            JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
-            return ifs; /* return untouched list */ \
-        } \
-    } while(0)
-
-
 /*
- * Frees an interface list (including any attached addresses)
+ * Frees an interface list (including any attached addresses).
  */
-void freeif(netif *ifs) {
+static void freeif(netif *ifs) {
     netif *currif = ifs;
     netif *child = NULL;
 
@@ -865,9 +856,10 @@
     }
 }
 
-netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
-             struct sockaddr *ifr_addrP, struct sockaddr *ifr_broadaddrP,
-             struct sockaddr *ifr_subnetaddrP, int family, short prefix)
+static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
+                    struct sockaddr *ifr_addrP,
+                    struct sockaddr *ifr_broadaddrP,
+                    int family, short prefix)
 {
     netif *currif = ifs, *parent;
     netaddr *addrP;
@@ -881,7 +873,6 @@
 #endif
 
     char *name_colonP;
-    int mask;
     int isVirtual = 0;
     int addr_size;
     int flags = 0;
@@ -894,12 +885,12 @@
     name[ifnam_size - 1] = '\0';
     *vname = 0;
 
-     // Create and populate the netaddr node. If allocation fails
-     // return an un-updated list.
+    // Create and populate the netaddr node. If allocation fails
+    // return an un-updated list.
 
-     // Allocate for addr and brdcast at once
+    // Allocate for addr and brdcast at once
 
-#ifdef AF_INET6
+#if defined(AF_INET6)
     addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in)
                                     : sizeof(struct sockaddr_in6);
 #else
@@ -911,33 +902,16 @@
     memcpy(addrP->addr, ifr_addrP, addr_size);
 
     addrP->family = family;
-    addrP->brdcast = NULL;
     addrP->mask = prefix;
     addrP->next = 0;
-    if (family == AF_INET) {
-        // Deal with broadcast addr & subnet mask
-        if (ifr_broadaddrP != NULL) {  // just set it, if already known
-            addrP->brdcast =
-                (struct sockaddr *)((char *)addrP + sizeof(netaddr) + addr_size);
-            memcpy(addrP->brdcast, ifr_broadaddrP, addr_size);
-        } else {  // otherwise look it up
-            struct sockaddr *brdcast_to =
-                (struct sockaddr *)((char *)addrP + sizeof(netaddr) + addr_size);
-            addrP->brdcast = getBroadcast(env, sock, name, brdcast_to);
-            if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
-                return ifs;
-            }
-        }
 
-        if (ifr_subnetaddrP != NULL) {  // just compute the mask, if already known
-            addrP->mask = computeMaskFromAddress(ifr_subnetaddrP);
-        } else {   // otherwise look it up
-            if ((mask = getSubnet(env, sock, name)) != -1) {
-                addrP->mask = mask;
-            } else if((*env)->ExceptionCheck(env)) {
-                return ifs;
-            }
-        }
+    // for IPv4 add broadcast address
+    if (family == AF_INET && ifr_broadaddrP != NULL) {
+        addrP->brdcast = (struct sockaddr *)
+                             ((char *)addrP + sizeof(netaddr) + addr_size);
+        memcpy(addrP->brdcast, ifr_broadaddrP, addr_size);
+    } else {
+        addrP->brdcast = NULL;
     }
 
     // Deal with virtual interface with colon notation e.g. eth0:1
@@ -1037,18 +1011,55 @@
     return ifs;
 }
 
-static short computeMaskFromAddress(struct sockaddr *ifr_subnetaddrP) {
-    short ret = 0;
-    unsigned int mask;
+/*
+ * Determines the prefix value for an AF_INET subnet address.
+ */
+static short translateIPv4AddressToPrefix(struct sockaddr_in *addr) {
+    short prefix = 0;
+    unsigned int mask = ntohl(addr->sin_addr.s_addr);
+    while (mask) {
+        mask <<= 1;
+        prefix++;
+    }
+    return prefix;
+}
+
+/*
+ * Determines the prefix value for an AF_INET6 subnet address.
+ */
+static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr) {
+    short prefix = 0;
+    u_char *addrBytes = (u_char *)&(addr->sin6_addr);
+    unsigned int byte, bit;
 
-    mask = ntohl(((struct sockaddr_in*)ifr_subnetaddrP)->sin_addr.s_addr);
-
-    while (mask) {
-       mask <<= 1;
-       ret++;
+    for (byte = 0; byte < sizeof(struct in6_addr); byte++, prefix += 8) {
+        if (addrBytes[byte] != 0xff) {
+            break;
+        }
+    }
+    if (byte != sizeof(struct in6_addr)) {
+        for (bit = 7; bit != 0; bit--, prefix++) {
+            if (!(addrBytes[byte] & (1 << bit))) {
+                break;
+            }
+        }
+        for (; bit != 0; bit--) {
+            if (addrBytes[byte] & (1 << bit)) {
+                prefix = 0;
+                break;
+            }
+        }
+        if (prefix > 0) {
+            byte++;
+            for (; byte < sizeof(struct in6_addr); byte++) {
+                if (addrBytes[byte]) {
+                    prefix = 0;
+                }
+            }
+        }
     }
 
-    return ret;
+    return prefix;
 }
 
 /*
@@ -1070,19 +1081,16 @@
     return sock;
 }
 
-
-/** Linux, AIX **/
-#if defined(__linux__) || defined(_AIX)
+/** Linux **/
+#if defined(__linux__)
 
-#ifdef AF_INET6
+#if defined(AF_INET6)
 /*
- * Opens a socket for further ioct calls. Tries AF_INET socket first and
- * if it falls return AF_INET6 socket.
+ * Opens a socket for further ioctl calls. Tries AF_INET socket first and
+ * if it fails return AF_INET6 socket.
  */
-// unused arg ifname and struct if2
 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;
-    struct ifreq if2;
 
     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
@@ -1102,23 +1110,22 @@
     // IPv6 socket regardless of type of address of an interface.
     return sock;
 }
-
 #else
 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
-    return openSocket(env,AF_INET);
+    return openSocket(env, AF_INET);
 }
 #endif
 
+/*
+ * Enumerates and returns all IPv4 interfaces on Linux.
+ */
 static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
     struct ifconf ifc;
     struct ifreq *ifreqP;
     char *buf = NULL;
-    int numifs;
     unsigned i;
-    int siocgifconfRequest = SIOCGIFCONF;
 
-#if defined(__linux__)
-    // need to do a dummy SIOCGIFCONF to determine the buffer size.
+    // do a dummy SIOCGIFCONF to determine the buffer size
     // SIOCGIFCOUNT doesn't work
     ifc.ifc_buf = NULL;
     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
@@ -1126,160 +1133,9 @@
             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
         return ifs;
     }
-#elif defined(_AIX)
-    ifc.ifc_buf = NULL;
-    if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
-        return ifs;
-    }
-#endif /* __linux__ */
 
+    // call SIOCGIFCONF to enumerate the interfaces
     CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
-
-    ifc.ifc_buf = buf;
-#if defined(_AIX)
-    siocgifconfRequest = CSIOCGIFCONF;
-#endif
-    if (ioctl(sock, siocgifconfRequest, (char *)&ifc) < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
-        free(buf);
-        return ifs;
-    }
-
-    // Iterate through each interface
-    ifreqP = ifc.ifc_req;
-    struct sockaddr addr, broadaddr, netmask;
-    for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
-        struct sockaddr* broadaddrP = NULL;
-        struct sockaddr* subnetaddrP = NULL;
-
-        // Ignore non IPv4 Interfaces
-        if ((struct sockaddr *)&(ifreqP->ifr_addr) != NULL &&
-            ((struct sockaddr *)&(ifreqP->ifr_addr))->sa_family != AF_INET) {
-            continue;
-        }
-
-        memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
-
-        // set broadaddrP, if applicable
-        if ((ifreqP->ifr_flags & IFF_POINTOPOINT) == 0 &&
-            ifreqP->ifr_flags & IFF_BROADCAST) {
-
-            if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
-                memcpy(&broadaddr, &(ifreqP->ifr_broadaddr), sizeof(struct sockaddr));
-                broadaddrP = &broadaddr;
-            }
-            // restore the address, for subsequent calls
-            memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
-        }
-
-        if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
-#if defined(_AIX)
-            memcpy(&netmask, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
-#else
-            memcpy(&netmask, &(ifreqP->ifr_netmask), sizeof(struct sockaddr));
-#endif
-            subnetaddrP = &netmask;
-        }
-
-        // Add to the list
-        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
-                    &addr, broadaddrP, subnetaddrP, AF_INET, 0);
-
-        // If an exception occurred then free the list
-        if ((*env)->ExceptionOccurred(env)) {
-            free(buf);
-            freeif(ifs);
-            return NULL;
-        }
-    }
-
-    // Free socket and buffer
-    free(buf);
-    return ifs;
-}
-
-
-#if defined(AF_INET6) && defined(__linux__)
-
-/*
- * Enumerates and returns all IPv6 interfaces on Linux.
- */
-static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
-    FILE *f;
-    char addr6[40], devname[21];
-    char addr6p[8][5];
-    int prefix, scope, dad_status, if_idx;
-    uint8_t ipv6addr[16];
-
-    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
-        while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
-                      addr6p[0], addr6p[1], addr6p[2], addr6p[3],
-                      addr6p[4], addr6p[5], addr6p[6], addr6p[7],
-                      &if_idx, &prefix, &scope, &dad_status, devname) != EOF) {
-
-            struct netif *ifs_ptr = NULL;
-            struct netif *last_ptr = NULL;
-            struct sockaddr_in6 addr;
-
-            sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
-                    addr6p[0], addr6p[1], addr6p[2], addr6p[3],
-                    addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
-            inet_pton(AF_INET6, addr6, ipv6addr);
-
-            memset(&addr, 0, sizeof(struct sockaddr_in6));
-            memcpy((void*)addr.sin6_addr.s6_addr, (const void*)ipv6addr, 16);
-
-            addr.sin6_scope_id = if_idx;
-
-            ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr,
-                        NULL, NULL, AF_INET6, (short)prefix);
-
-            // If an exception occurred then return the list as is.
-            if ((*env)->ExceptionOccurred(env)) {
-                fclose(f);
-                return ifs;
-            }
-       }
-       fclose(f);
-    }
-    return ifs;
-}
-#endif
-
-
-#if defined(AF_INET6) && defined(_AIX)
-
-/*
- * Enumerates and returns all IPv6 interfaces on AIX.
- */
-static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
-    struct ifconf ifc;
-    struct ifreq *ifreqP;
-    char *buf;
-    int numifs;
-    unsigned i;
-    unsigned bufsize;
-    char *cp, *cplimit;
-
-    // use SIOCGSIZIFCONF to get size for  SIOCGIFCONF
-
-    ifc.ifc_buf = NULL;
-    if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
-        return ifs;
-    }
-    bufsize = ifc.ifc_len;
-
-    buf = (char *)malloc(bufsize);
-    if (!buf) {
-        JNU_ThrowOutOfMemoryError(env, "Network interface native buffer allocation failed");
-        return ifs;
-    }
-    ifc.ifc_len = bufsize;
     ifc.ifc_buf = buf;
     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
         JNU_ThrowByNameWithMessageAndLastError
@@ -1288,41 +1144,48 @@
         return ifs;
     }
 
-    // Iterate through each interface
+    // iterate through each interface
     ifreqP = ifc.ifc_req;
-    cp = (char *)ifc.ifc_req;
-    cplimit = cp + ifc.ifc_len;
+    for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
+        struct sockaddr addr, broadaddr, *broadaddrP = NULL;
+        short prefix = 0;
+
+        // ignore non IPv4 interfaces
+        if (ifreqP->ifr_addr.sa_family != AF_INET) {
+            continue;
+        }
 
-    for (; cp < cplimit;
-        cp += (sizeof(ifreqP->ifr_name) +
-               MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr))))
-    {
-        ifreqP = (struct ifreq *)cp;
-        struct ifreq if2;
-        memset((char *)&if2, 0, sizeof(if2));
-        strncpy(if2.ifr_name, ifreqP->ifr_name, sizeof(if2.ifr_name) - 1);
+        // save socket address
+        memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
+
+        // determine broadcast address, if applicable
+        if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&
+            ifreqP->ifr_flags & IFF_BROADCAST) {
 
-        // Skip interface that aren't UP
-        if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) >= 0) {
-            if (!(if2.ifr_flags & IFF_UP)) {
-                continue;
+            // restore socket address to ifreqP
+            memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
+
+            if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
+                memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),
+                       sizeof(struct sockaddr));
+                broadaddrP = &broadaddr;
             }
         }
 
-        if (ifreqP->ifr_addr.sa_family != AF_INET6)
-            continue;
+        // restore socket address to ifreqP
+        memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
 
-        if (ioctl(sock, SIOCGIFSITE6, (char *)&if2) >= 0) {
-            struct sockaddr_in6 *s6= (struct sockaddr_in6 *)&(ifreqP->ifr_addr);
-            s6->sin6_scope_id = if2.ifr_site6;
+        // determine netmask
+        if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
+            prefix = translateIPv4AddressToPrefix(
+                         (struct sockaddr_in *)&(ifreqP->ifr_netmask));
         }
 
-        // Add to the list
+        // add interface to the list
         ifs = addif(env, sock, ifreqP->ifr_name, ifs,
-                    (struct sockaddr *)&(ifreqP->ifr_addr),
-                    NULL, NULL, AF_INET6, 0);
+                    &addr, broadaddrP, AF_INET, prefix);
 
-        // If an exception occurred then free the list
+        // in case of exception, free interface list and buffer and return NULL
         if ((*env)->ExceptionOccurred(env)) {
             free(buf);
             freeif(ifs);
@@ -1330,18 +1193,60 @@
         }
     }
 
-    // Free socket and buffer
+    // free buffer
     free(buf);
     return ifs;
 }
-#endif
+
+#if defined(AF_INET6)
+
+/*
+ * Enumerates and returns all IPv6 interfaces on Linux.
+ */
+static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
+    FILE *f;
+    char devname[21], addr6p[8][5];
+    int prefix, scope, dad_status, if_idx;
+
+    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
+        while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
+                      addr6p[0], addr6p[1], addr6p[2], addr6p[3],
+                      addr6p[4], addr6p[5], addr6p[6], addr6p[7],
+                      &if_idx, &prefix, &scope, &dad_status, devname) != EOF) {
+
+            char addr6[40];
+            struct sockaddr_in6 addr;
+
+            sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
+                    addr6p[0], addr6p[1], addr6p[2], addr6p[3],
+                    addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
 
+            memset(&addr, 0, sizeof(struct sockaddr_in6));
+            inet_pton(AF_INET6, addr6, (void*)addr.sin6_addr.s6_addr);
 
+            // set scope ID to interface index
+            addr.sin6_scope_id = if_idx;
+
+            // add interface to the list
+            ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr,
+                        NULL, AF_INET6, (short)prefix);
+
+            // if an exception occurred then return the list as is
+            if ((*env)->ExceptionOccurred(env)) {
+                break;
+            }
+       }
+       fclose(f);
+    }
+    return ifs;
+}
+
+#endif /* AF_INET6 */
+
+/*
+ * Try to get the interface index.
+ */
 static int getIndex(int sock, const char *name) {
-     // Try to get the interface index
-#if defined(_AIX)
-    return if_nametoindex(name);
-#else
     struct ifreq if2;
     memset((char *)&if2, 0, sizeof(if2));
     strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);
@@ -1351,61 +1256,6 @@
     }
 
     return if2.ifr_ifindex;
-#endif
-}
-
-/*
- * Returns the IPv4 broadcast address of a named interface, if it exists.
- * Returns 0 if it doesn't have one.
- */
-static struct sockaddr *getBroadcast
-  (JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store)
-{
-    struct sockaddr *ret = NULL;
-    struct ifreq if2;
-    memset((char *)&if2, 0, sizeof(if2));
-    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
-
-    // Let's make sure the interface does have a broadcast address.
-    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2)  < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFFLAGS) failed");
-        return ret;
-    }
-
-    if (if2.ifr_flags & IFF_BROADCAST) {
-        // It does, let's retrieve it
-        if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) < 0) {
-            JNU_ThrowByNameWithMessageAndLastError
-                (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFBRDADDR) failed");
-            return ret;
-        }
-
-        ret = brdcast_store;
-        memcpy(ret, &if2.ifr_broadaddr, sizeof(struct sockaddr));
-    }
-
-    return ret;
-}
-
-/*
- * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
- * interface, if it has one, otherwise return -1.
- */
-static short getSubnet(JNIEnv *env, int sock, const char *ifname) {
-    unsigned int mask;
-    short ret;
-    struct ifreq if2;
-    memset((char *)&if2, 0, sizeof(if2));
-    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
-
-    if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFNETMASK) failed");
-        return -1;
-    }
-
-    return computeMaskFromAddress(&(if2.ifr_addr));
 }
 
 /*
@@ -1414,10 +1264,272 @@
  * MAC address. Returns -1 if there is no hardware address on that interface.
  */
 static int getMacAddress
-  (JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr,
+  (JNIEnv *env, int sock, const char *ifname, const struct in_addr *addr,
    unsigned char *buf)
 {
-#if defined (_AIX)
+    static struct ifreq ifr;
+    int i;
+    memset((char *)&ifr, 0, sizeof(ifr));
+    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFHWADDR) failed");
+        return -1;
+    }
+
+    memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
+
+    // all bytes to 0 means no hardware address
+    for (i = 0; i < IFHWADDRLEN; i++) {
+        if (buf[i] != 0)
+            return IFHWADDRLEN;
+    }
+
+    return -1;
+}
+
+static int getMTU(JNIEnv *env, int sock, const char *ifname) {
+    struct ifreq if2;
+    memset((char *)&if2, 0, sizeof(if2));
+    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
+
+    if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
+        return -1;
+    }
+
+    return if2.ifr_mtu;
+}
+
+static int getFlags(int sock, const char *ifname, int *flags) {
+    struct ifreq if2;
+    memset((char *)&if2, 0, sizeof(if2));
+    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
+
+    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
+        return -1;
+    }
+
+    if (sizeof(if2.ifr_flags) == sizeof(short)) {
+        *flags = (if2.ifr_flags & 0xffff);
+    } else {
+        *flags = if2.ifr_flags;
+    }
+    return 0;
+}
+
+#endif /* __linux__ */
+
+/** AIX **/
+#if defined(_AIX)
+
+#if defined(AF_INET6)
+/*
+ * Opens a socket for further ioctl calls. Tries AF_INET socket first and
+ * if it fails return AF_INET6 socket.
+ */
+static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
+    int sock;
+
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        if (errno == EPROTONOSUPPORT) {
+            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+                JNU_ThrowByNameWithMessageAndLastError
+                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
+                return -1;
+            }
+        } else { // errno is not NOSUPPORT
+            JNU_ThrowByNameWithMessageAndLastError
+                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
+            return -1;
+        }
+    }
+
+    return sock;
+}
+#else
+static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
+    return openSocket(env, AF_INET);
+}
+#endif
+
+/*
+ * Enumerates and returns all IPv4 interfaces on AIX.
+ */
+static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
+    struct ifconf ifc;
+    struct ifreq *ifreqP;
+    char *buf = NULL;
+    unsigned i;
+
+    // call SIOCGSIZIFCONF to get the size of SIOCGIFCONF buffer
+    if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
+        return ifs;
+    }
+
+    // call CSIOCGIFCONF instead of SIOCGIFCONF where interface
+    // records will always have sizeof(struct ifreq) length.
+    // Be aware that only IPv4 data is complete this way.
+    CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
+    ifc.ifc_buf = buf;
+    if (ioctl(sock, CSIOCGIFCONF, (char *)&ifc) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(CSIOCGIFCONF) failed");
+        free(buf);
+        return ifs;
+    }
+
+    // iterate through each interface
+    ifreqP = ifc.ifc_req;
+    for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
+        struct sockaddr addr, broadaddr, *broadaddrP = NULL;
+        short prefix = 0;
+
+        // ignore non IPv4 interfaces
+        if (ifreqP->ifr_addr.sa_family != AF_INET) {
+            continue;
+        }
+
+        // save socket address
+        memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
+
+        // determine broadcast address, if applicable
+        if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&
+            ifreqP->ifr_flags & IFF_BROADCAST) {
+
+            // restore socket address to ifreqP
+            memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
+
+            if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
+                memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),
+                       sizeof(struct sockaddr));
+                broadaddrP = &broadaddr;
+            }
+        }
+
+        // restore socket address to ifreqP
+        memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
+
+        // determine netmask
+        if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
+            prefix = translateIPv4AddressToPrefix(
+                         (struct sockaddr_in *)&(ifreqP->ifr_addr));
+        }
+
+        // add interface to the list
+        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
+                    &addr, broadaddrP, AF_INET, prefix);
+
+        // in case of exception, free interface list and buffer and return NULL
+        if ((*env)->ExceptionOccurred(env)) {
+            free(buf);
+            freeif(ifs);
+            return NULL;
+        }
+    }
+
+    // free buffer
+    free(buf);
+    return ifs;
+}
+
+#if defined(AF_INET6)
+
+/*
+ * Enumerates and returns all IPv6 interfaces on AIX.
+ */
+static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
+    struct ifconf ifc;
+    struct ifreq *ifreqP;
+    char *buf;
+
+    // call SIOCGSIZIFCONF to get size for SIOCGIFCONF buffer
+    if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
+        return ifs;
+    }
+
+    // call SIOCGIFCONF to enumerate the interfaces
+    CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
+    ifc.ifc_buf = buf;
+    if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
+        free(buf);
+        return ifs;
+    }
+
+    // iterate through each interface
+    char *cp = (char *)ifc.ifc_req;
+    char *cplimit = cp + ifc.ifc_len;
+
+    for (; cp < cplimit;
+         cp += (sizeof(ifreqP->ifr_name) +
+                MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr))))
+    {
+        ifreqP = (struct ifreq *)cp;
+        short prefix = 0;
+
+        // ignore non IPv6 interfaces
+        if (ifreqP->ifr_addr.sa_family != AF_INET6) {
+            continue;
+        }
+
+        // determine netmask
+        struct in6_ifreq if6;
+        memset((char *)&if6, 0, sizeof(if6));
+        strncpy(if6.ifr_name, ifreqP->ifr_name, sizeof(if6.ifr_name) - 1);
+        memcpy(&(if6.ifr_Addr), &(ifreqP->ifr_addr),
+               sizeof(struct sockaddr_in6));
+        if (ioctl(sock, SIOCGIFNETMASK6, (char *)&if6) >= 0) {
+            prefix = translateIPv6AddressToPrefix(&(if6.ifr_Addr));
+        }
+
+        // set scope ID to interface index
+        ((struct sockaddr_in6 *)&(ifreqP->ifr_addr))->sin6_scope_id =
+            getIndex(sock, ifreqP->ifr_name);
+
+        // add interface to the list
+        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
+                    (struct sockaddr *)&(ifreqP->ifr_addr),
+                    NULL, AF_INET6, prefix);
+
+        // if an exception occurred then free the list
+        if ((*env)->ExceptionOccurred(env)) {
+            free(buf);
+            freeif(ifs);
+            return NULL;
+        }
+    }
+
+    // free buffer
+    free(buf);
+    return ifs;
+}
+
+#endif /* AF_INET6 */
+
+/*
+ * Try to get the interface index.
+ */
+static int getIndex(int sock, const char *name) {
+    int index = if_nametoindex(name);
+    return (index == 0) ? -1 : index;
+}
+
+/*
+ * Gets the Hardware address (usually MAC address) for the named interface.
+ * On return puts the data in buf, and returns the length, in byte, of the
+ * MAC address. Returns -1 if there is no hardware address on that interface.
+ */
+static int getMacAddress
+  (JNIEnv *env, int sock, const char *ifname, const struct in_addr *addr,
+   unsigned char *buf)
+{
     int size;
     struct kinfo_ndd *nddp;
     void *end;
@@ -1457,40 +1569,12 @@
     }
 
     return -1;
-#elif defined(__linux__)
-    static struct ifreq ifr;
-    int i;
-    memset((char *)&ifr, 0, sizeof(ifr));
-    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
-    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFHWADDR) failed");
-        return -1;
-    }
-
-    memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
-
-    // All bytes to 0 means no hardware address.
-
-    for (i = 0; i < IFHWADDRLEN; i++) {
-        if (buf[i] != 0)
-            return IFHWADDRLEN;
-    }
-
-    return -1;
-#endif
 }
 
-static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
+static int getMTU(JNIEnv *env, int sock, const char *ifname) {
     struct ifreq if2;
     memset((char *)&if2, 0, sizeof(if2));
-
-    if (ifname != NULL) {
-        strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
-    } else {
-        JNU_ThrowNullPointerException(env, "network interface name is NULL");
-        return -1;
-    }
+    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
 
     if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
         JNU_ThrowByNameWithMessageAndLastError
@@ -1498,7 +1582,7 @@
         return -1;
     }
 
-    return  if2.ifr_mtu;
+    return if2.ifr_mtu;
 }
 
 static int getFlags(int sock, const char *ifname, int *flags) {
@@ -1518,16 +1602,16 @@
   return 0;
 }
 
-#endif  /* defined(__linux__) || defined(_AIX) */
+#endif /* _AIX */
 
 /** Solaris **/
 #if defined(__solaris__)
 
+#if defined(AF_INET6)
 /*
- * Opens a socket for further ioct calls. Tries AF_INET socket first and
- * if it falls return AF_INET6 socket.
+ * Opens a socket for further ioctl calls. Tries AF_INET socket first and
+ * if it fails return AF_INET6 socket.
  */
-#ifdef AF_INET6
 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock, alreadyV6 = 0;
     struct lifreq if2;
@@ -1539,8 +1623,7 @@
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
             }
-
-            alreadyV6=1;
+            alreadyV6 = 1;
         } else { // errno is not NOSUPPORT
             JNU_ThrowByNameWithMessageAndLastError
                 (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
@@ -1548,14 +1631,12 @@
         }
     }
 
-
     // Solaris requires that we have an IPv6 socket to query an  interface
     // without an IPv4 address - check it here. POSIX 1 require the kernel to
     // return ENOTTY if the call is inappropriate for a device e.g. the NETMASK
     // for a device having IPv6 only address but not all devices follow the
     // standard so fall back on any error. It's not an ecologically friendly
     // gesture but more reliable.
-
     if (!alreadyV6) {
         memset((char *)&if2, 0, sizeof(if2));
         strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
@@ -1571,40 +1652,24 @@
 
     return sock;
 }
-
 #else
 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
-    return openSocket(env,AF_INET);
+    return openSocket(env, AF_INET);
 }
 #endif
 
 /*
- * Enumerates and returns all IPv4 interfaces.
+ * Enumerates and returns all IPv4 interfaces on Solaris.
  */
 static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
-    return enumIPvXInterfaces(env,sock, ifs, AF_INET);
-}
-
-#ifdef AF_INET6
-static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
-    return enumIPvXInterfaces(env,sock, ifs, AF_INET6);
-}
-#endif
+    struct lifconf ifc;
+    struct lifreq *ifreqP;
+    struct lifnum numifs;
+    char *buf = NULL;
+    unsigned i;
 
-/*
- * Enumerates and returns all interfaces on Solaris.
- * Uses the same code for IPv4 and IPv6.
- */
-static netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family) {
-    struct lifconf ifc;
-    struct lifreq *ifr;
-    int n;
-    char *buf;
-    struct lifnum numifs;
-    unsigned bufsize;
-
-    // Get the interface count
-    numifs.lifn_family = family;
+    // call SIOCGLIFNUM to get the size of SIOCGIFCONF buffer
+    numifs.lifn_family = AF_INET;
     numifs.lifn_flags = 0;
     if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
         JNU_ThrowByNameWithMessageAndLastError
@@ -1612,14 +1677,12 @@
         return ifs;
     }
 
-    //  Enumerate the interface configurations
-    bufsize = numifs.lifn_count * sizeof (struct lifreq);
-    CHECKED_MALLOC3(buf, char *, bufsize);
-
-    ifc.lifc_family = family;
+    // call SIOCGLIFCONF to enumerate the interfaces
+    ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);
+    CHECKED_MALLOC3(buf, char *, ifc.lifc_len);
+    ifc.lifc_buf = buf;
+    ifc.lifc_family = AF_INET;
     ifc.lifc_flags = 0;
-    ifc.lifc_len = bufsize;
-    ifc.lifc_buf = buf;
     if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
         JNU_ThrowByNameWithMessageAndLastError
             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");
@@ -1627,43 +1690,119 @@
         return ifs;
     }
 
-    // Iterate through each interface
-    ifr = ifc.lifc_req;
-    for (n=0; n<numifs.lifn_count; n++, ifr++) {
-        int index = -1;
-        struct lifreq if2;
+    // iterate through each interface
+    ifreqP = ifc.lifc_req;
+    for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {
+        struct sockaddr addr, *broadaddrP = NULL;
 
-        // Ignore either IPv4 or IPv6 addresses
-        if (ifr->lifr_addr.ss_family != family) {
+        // ignore non IPv4 interfaces
+        if (ifreqP->lifr_addr.ss_family != AF_INET) {
             continue;
         }
 
-#ifdef AF_INET6
-        if (ifr->lifr_addr.ss_family == AF_INET6) {
-            struct sockaddr_in6 *s6= (struct sockaddr_in6 *)&(ifr->lifr_addr);
-            s6->sin6_scope_id = getIndex(sock, ifr->lifr_name);
+        // save socket address
+        memcpy(&addr, &(ifreqP->lifr_addr), sizeof(struct sockaddr));
+
+        // determine broadcast address, if applicable
+        if ((ioctl(sock, SIOCGLIFFLAGS, ifreqP) == 0) &&
+            ifreqP->lifr_flags & IFF_BROADCAST) {
+
+            // restore socket address to ifreqP
+            memcpy(&(ifreqP->lifr_addr), &addr, sizeof(struct sockaddr));
+
+            // query broadcast address and set pointer to it
+            if (ioctl(sock, SIOCGLIFBRDADDR, ifreqP) == 0) {
+                broadaddrP = (struct sockaddr *)&(ifreqP->lifr_broadaddr);
+            }
         }
-#endif
 
         // add to the list
-        ifs = addif(env, sock,ifr->lifr_name, ifs,
-                    (struct sockaddr *)&(ifr->lifr_addr),
-                    NULL, NULL, family, (short)ifr->lifr_addrlen);
+        ifs = addif(env, sock, ifreqP->lifr_name, ifs,
+                    &addr, broadaddrP, AF_INET, (short)ifreqP->lifr_addrlen);
 
-        // If an exception occurred we return immediately
+        // if an exception occurred we return immediately
         if ((*env)->ExceptionOccurred(env)) {
             free(buf);
             return ifs;
         }
-
    }
 
+    // free buffer
     free(buf);
     return ifs;
 }
 
+#if defined(AF_INET6)
+
+/*
+ * Enumerates and returns all IPv6 interfaces on Solaris.
+ */
+static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
+    struct lifconf ifc;
+    struct lifreq *ifreqP;
+    struct lifnum numifs;
+    char *buf = NULL;
+    unsigned i;
+
+    // call SIOCGLIFNUM to get the size of SIOCGLIFCONF buffer
+    numifs.lifn_family = AF_INET6;
+    numifs.lifn_flags = 0;
+    if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");
+        return ifs;
+    }
+
+    // call SIOCGLIFCONF to enumerate the interfaces
+    ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);
+    CHECKED_MALLOC3(buf, char *, ifc.lifc_len);
+    ifc.lifc_buf = buf;
+    ifc.lifc_family = AF_INET6;
+    ifc.lifc_flags = 0;
+    if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");
+        free(buf);
+        return ifs;
+    }
+
+    // iterate through each interface
+    ifreqP = ifc.lifc_req;
+    for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {
+
+        // ignore non IPv6 interfaces
+        if (ifreqP->lifr_addr.ss_family != AF_INET6) {
+            continue;
+        }
+
+        // set scope ID to interface index
+        ((struct sockaddr_in6 *)&(ifreqP->lifr_addr))->sin6_scope_id =
+            getIndex(sock, ifreqP->lifr_name);
+
+        // add to the list
+        ifs = addif(env, sock, ifreqP->lifr_name, ifs,
+                    (struct sockaddr *)&(ifreqP->lifr_addr),
+                    NULL, AF_INET6, (short)ifreqP->lifr_addrlen);
+
+        // if an exception occurred we return immediately
+        if ((*env)->ExceptionOccurred(env)) {
+            free(buf);
+            return ifs;
+        }
+   }
+
+    // free buffer
+    free(buf);
+    return ifs;
+}
+
+#endif /* AF_INET6 */
+
+/*
+ * Try to get the interface index.
+ * (Not supported on Solaris 2.6 or 7)
+ */
 static int getIndex(int sock, const char *name) {
-    // Try to get the interface index.  (Not supported on Solaris 2.6 or 7)
     struct lifreq if2;
     memset((char *)&if2, 0, sizeof(if2));
     strncpy(if2.lifr_name, name, sizeof(if2.lifr_name) - 1);
@@ -1676,69 +1815,12 @@
 }
 
 /*
- * Returns the IPv4 broadcast address of a named interface, if it exists.
- * Returns 0 if it doesn't have one.
- */
-static struct sockaddr *getBroadcast
-  (JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store)
-{
-    struct sockaddr *ret = NULL;
-    struct lifreq if2;
-    memset((char *)&if2, 0, sizeof(if2));
-    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
-
-    // Let's make sure the interface does have a broadcast address
-    if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2)  < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFFLAGS) failed");
-        return ret;
-    }
-
-    if (if2.lifr_flags & IFF_BROADCAST) {
-        // It does, let's retrieve it
-        if (ioctl(sock, SIOCGLIFBRDADDR, (char *)&if2) < 0) {
-            JNU_ThrowByNameWithMessageAndLastError
-                (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFBRDADDR) failed");
-            return ret;
-        }
-
-        ret = brdcast_store;
-        memcpy(ret, &if2.lifr_broadaddr, sizeof(struct sockaddr));
-    }
-
-    return ret;
-}
-
-/*
- * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
- * interface, if it has one, otherwise return -1.
- */
-static short getSubnet(JNIEnv *env, int sock, const char *ifname) {
-    unsigned int mask;
-    short ret;
-    struct lifreq if2;
-    memset((char *)&if2, 0, sizeof(if2));
-    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
-
-    if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNETMASK) failed");
-        return -1;
-    }
-
-    return computeMaskFromAddress(&(if2.lifr_addr));
-}
-
-
-#define DEV_PREFIX  "/dev/"
-
-/*
  * Solaris specific DLPI code to get hardware address from a device.
  * Unfortunately, at least up to Solaris X, you have to have special
  * privileges (i.e. be root).
  */
 static int getMacFromDevice
-  (JNIEnv *env, const char* ifname, unsigned char* retbuf)
+  (JNIEnv *env, const char *ifname, unsigned char *retbuf)
 {
     char style1dev[MAXPATHLEN];
     int fd;
@@ -1796,23 +1878,20 @@
  * MAC address. Returns -1 if there is no hardware address on that interface.
  */
 static int getMacAddress
-  (JNIEnv *env, int sock, const char *ifname, const struct in_addr* addr,
+  (JNIEnv *env, int sock, const char *ifname, const struct in_addr *addr,
    unsigned char *buf)
 {
-    struct arpreq arpreq;
-    struct sockaddr_in* sin;
-    struct sockaddr_in ipAddr;
+    struct lifreq if2;
     int len, i;
-    struct lifreq lif;
 
     // First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails
     // try the old way.
-    memset(&lif, 0, sizeof(lif));
-    strlcpy(lif.lifr_name, ifname, sizeof(lif.lifr_name));
+    memset((char *)&if2, 0, sizeof(if2));
+    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
 
-    if (ioctl(sock, SIOCGLIFHWADDR, &lif) != -1) {
+    if (ioctl(sock, SIOCGLIFHWADDR, &if2) != -1) {
         struct sockaddr_dl *sp;
-        sp = (struct sockaddr_dl *)&lif.lifr_addr;
+        sp = (struct sockaddr_dl *)&if2.lifr_addr;
         memcpy(buf, &sp->sdl_data[0], sp->sdl_alen);
         return sp->sdl_alen;
     }
@@ -1823,6 +1902,10 @@
     if ((len = getMacFromDevice(env, ifname, buf))  == 0) {
         // DLPI failed - trying to do arp lookup
 
+        struct arpreq arpreq;
+        struct sockaddr_in *sin;
+        struct sockaddr_in ipAddr;
+
         if (addr == NULL) {
              // No IPv4 address for that interface, so can't do an ARP lookup.
              return -1;
@@ -1830,8 +1913,8 @@
 
          len = 6; //???
 
-         sin = (struct sockaddr_in *) &arpreq.arp_pa;
-         memset((char *) &arpreq, 0, sizeof(struct arpreq));
+         sin = (struct sockaddr_in *)&arpreq.arp_pa;
+         memset((char *)&arpreq, 0, sizeof(struct arpreq));
          ipAddr.sin_port = 0;
          ipAddr.sin_family = AF_INET;
          memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr));
@@ -1842,19 +1925,19 @@
              return -1;
          }
 
-         memcpy(buf, &arpreq.arp_ha.sa_data[0], len );
+         memcpy(buf, &arpreq.arp_ha.sa_data[0], len);
     }
 
-    // All bytes to 0 means no hardware address.
+    // all bytes to 0 means no hardware address
     for (i = 0; i < len; i++) {
-      if (buf[i] != 0)
-         return len;
+        if (buf[i] != 0)
+            return len;
     }
 
     return -1;
 }
 
-static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
+static int getMTU(JNIEnv *env, int sock, const char *ifname) {
     struct lifreq if2;
     memset((char *)&if2, 0, sizeof(if2));
     strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
@@ -1881,47 +1964,43 @@
     return 0;
 }
 
-
-#endif  /* __solaris__ */
-
+#endif /* __solaris__ */
 
 /** BSD **/
-#ifdef _ALLBSD_SOURCE
+#if defined(_ALLBSD_SOURCE)
 
+#if defined(AF_INET6)
 /*
- * Opens a socket for further ioct calls. Tries AF_INET socket first and
- * if it falls return AF_INET6 socket.
+ * Opens a socket for further ioctl calls. Tries AF_INET socket first and
+ * if it fails return AF_INET6 socket.
  */
-#ifdef AF_INET6
 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;
-    struct ifreq if2;
 
-     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-         if (errno == EPROTONOSUPPORT) {
-              if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
-                 JNU_ThrowByNameWithMessageAndLastError
-                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
-                 return -1;
-              }
-         } else { // errno is not NOSUPPORT
-             JNU_ThrowByNameWithMessageAndLastError
-                 (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
-             return -1;
-         }
-   }
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        if (errno == EPROTONOSUPPORT) {
+            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+                JNU_ThrowByNameWithMessageAndLastError
+                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
+                return -1;
+            }
+        } else { // errno is not NOSUPPORT
+            JNU_ThrowByNameWithMessageAndLastError
+                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
+            return -1;
+        }
+    }
 
-   return sock;
+    return sock;
 }
-
 #else
 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
-    return openSocket(env,AF_INET);
+    return openSocket(env, AF_INET);
 }
 #endif
 
 /*
- * Enumerates and returns all IPv4 interfaces.
+ * Enumerates and returns all IPv4 interfaces on BSD.
  */
 static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
     struct ifaddrs *ifa, *origifa;
@@ -1933,23 +2012,25 @@
     }
 
     for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
-        struct sockaddr* ifa_broadaddr = NULL;
+        struct sockaddr *broadaddrP = NULL;
 
-        // Skip non-AF_INET entries.
+        // ignore non IPv4 interfaces
         if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
             continue;
 
         // set ifa_broadaddr, if there is one
         if ((ifa->ifa_flags & IFF_POINTOPOINT) == 0 &&
             ifa->ifa_flags & IFF_BROADCAST) {
-            ifa_broadaddr = ifa->ifa_broadaddr;
+            broadaddrP = ifa->ifa_dstaddr;
         }
 
-        // Add to the list.
+        // add interface to the list
         ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr,
-                    ifa_broadaddr, ifa->ifa_netmask, AF_INET, 0);
+                    broadaddrP, AF_INET,
+                    translateIPv4AddressToPrefix((struct sockaddr_in *)
+                                                 ifa->ifa_netmask));
 
-        // If an exception occurred then free the list.
+        // if an exception occurred then free the list
         if ((*env)->ExceptionOccurred(env)) {
             freeifaddrs(origifa);
             freeif(ifs);
@@ -1957,44 +2038,18 @@
         }
     }
 
-    // Free socket and buffer
+    // free ifaddrs buffer
     freeifaddrs(origifa);
     return ifs;
 }
 
-#ifdef AF_INET6
-/*
- * Determines the prefix on BSD for IPv6 interfaces.
- */
-static int prefix(void *val, int size) {
-    u_char *name = (u_char *)val;
-    int byte, bit, prefix = 0;
-
-    for (byte = 0; byte < size; byte++, prefix += 8)
-        if (name[byte] != 0xff)
-            break;
-    if (byte == size)
-        return prefix;
-    for (bit = 7; bit != 0; bit--, prefix++)
-        if (!(name[byte] & (1 << bit)))
-            break;
-    for (; bit != 0; bit--)
-        if (name[byte] & (1 << bit))
-            return (0);
-    byte++;
-    for (; byte < size; byte++)
-        if (name[byte])
-            return (0);
-    return prefix;
-}
+#if defined(AF_INET6)
 
 /*
  * Enumerates and returns all IPv6 interfaces on BSD.
  */
 static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
     struct ifaddrs *ifa, *origifa;
-    struct sockaddr_in6 *sin6;
-    struct in6_ifreq ifr6;
 
     if (getifaddrs(&origifa) != 0) {
         JNU_ThrowByNameWithMessageAndLastError
@@ -2003,31 +2058,21 @@
     }
 
     for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
-
-        // Skip non-AF_INET6 entries.
+        // ignore non IPv6 interfaces
         if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)
             continue;
 
-        memset(&ifr6, 0, sizeof(ifr6));
-        strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
-        memcpy(&ifr6.ifr_addr, ifa->ifa_addr,
-               MIN(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
+        // set scope ID to interface index
+        ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id =
+            getIndex(sock, ifa->ifa_name);
 
-        if (ioctl(sock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
-            JNU_ThrowByNameWithMessageAndLastError
-                (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFNETMASK_IN6) failed");
-            freeifaddrs(origifa);
-            freeif(ifs);
-            return NULL;
-        }
+        // add interface to the list
+        ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, NULL,
+                    AF_INET6,
+                    translateIPv6AddressToPrefix((struct sockaddr_in6 *)
+                                                 ifa->ifa_netmask));
 
-        // Add to the list.
-        sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
-        ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, NULL, NULL,
-                    AF_INET6,
-                    (short)prefix(&sin6->sin6_addr, sizeof(struct in6_addr)));
-
-        // If an exception occurred then free the list.
+        // if an exception occurred then free the list
         if ((*env)->ExceptionOccurred(env)) {
             freeifaddrs(origifa);
             freeif(ifs);
@@ -2035,16 +2080,21 @@
         }
     }
 
-    // Free socket and ifaddrs buffer
+    // free ifaddrs buffer
     freeifaddrs(origifa);
     return ifs;
 }
-#endif
+
+#endif /* AF_INET6 */
 
+/*
+ * Try to get the interface index.
+ */
 static int getIndex(int sock, const char *name) {
-#ifdef __FreeBSD__
-    // Try to get the interface index
-    // (Not supported on Solaris 2.6 or 7)
+#if !defined(__FreeBSD__)
+    int index = if_nametoindex(name);
+    return (index == 0) ? -1 : index;
+#else
     struct ifreq if2;
     memset((char *)&if2, 0, sizeof(if2));
     strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);
@@ -2054,74 +2104,16 @@
     }
 
     return if2.ifr_index;
-#else
-    // Try to get the interface index using BSD specific if_nametoindex
-    int index = if_nametoindex(name);
-    return (index == 0) ? -1 : index;
 #endif
 }
 
 /*
- * Returns the IPv4 broadcast address of a named interface, if it exists.
- * Returns 0 if it doesn't have one.
- */
-static struct sockaddr *getBroadcast
-  (JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store)
-{
-    struct sockaddr *ret = NULL;
-    struct ifreq if2;
-    memset((char *)&if2, 0, sizeof(if2));
-    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
-
-    // Make sure the interface does have a broadcast address
-    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFFLAGS) failed");
-        return ret;
-    }
-
-    if (if2.ifr_flags & IFF_BROADCAST) {
-        // It does, let's retrieve it
-        if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) < 0) {
-            JNU_ThrowByNameWithMessageAndLastError
-                (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFBRDADDR) failed");
-            return ret;
-        }
-
-        ret = brdcast_store;
-        memcpy(ret, &if2.ifr_broadaddr, sizeof(struct sockaddr));
-    }
-
-    return ret;
-}
-
-/*
- * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
- * interface, if it has one, otherwise return -1.
- */
-static short getSubnet(JNIEnv *env, int sock, const char *ifname) {
-    unsigned int mask;
-    short ret;
-    struct ifreq if2;
-    memset((char *)&if2, 0, sizeof(if2));
-    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
-
-    if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) < 0) {
-        JNU_ThrowByNameWithMessageAndLastError
-            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFNETMASK) failed");
-        return -1;
-    }
-
-    return computeMaskFromAddress(&(if2.ifr_addr));
-}
-
-/*
  * Gets the Hardware address (usually MAC address) for the named interface.
- * return puts the data in buf, and returns the length, in byte, of the
+ * On return puts the data in buf, and returns the length, in byte, of the
  * MAC address. Returns -1 if there is no hardware address on that interface.
  */
 static int getMacAddress
-  (JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr,
+  (JNIEnv *env, int sock, const char *ifname, const struct in_addr *addr,
    unsigned char *buf)
 {
     struct ifaddrs *ifa0, *ifa;
@@ -2150,7 +2142,7 @@
     return -1;
 }
 
-static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
+static int getMTU(JNIEnv *env, int sock, const char *ifname) {
     struct ifreq if2;
     memset((char *)&if2, 0, sizeof(if2));
     strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
@@ -2161,12 +2153,11 @@
         return -1;
     }
 
-    return  if2.ifr_mtu;
+    return if2.ifr_mtu;
 }
 
 static int getFlags(int sock, const char *ifname, int *flags) {
     struct ifreq if2;
-    int ret = -1;
     memset((char *)&if2, 0, sizeof(if2));
     strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
 
@@ -2181,4 +2172,4 @@
     }
     return 0;
 }
-#endif /* __ALLBSD_SOURCE__ */
+#endif /* _ALLBSD_SOURCE */
--- a/jdk/src/java.base/windows/classes/java/lang/ClassLoaderHelper.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/windows/classes/java/lang/ClassLoaderHelper.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.lang;
 
 import java.io.File;
--- a/jdk/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
+import java.security.SecureRandom;
 import java.util.Random;
 
 
@@ -47,24 +48,16 @@
 class PipeImpl
     extends Pipe
 {
+    // Number of bytes in the secret handshake.
+    private static final int NUM_SECRET_BYTES = 16;
+
+    // Random object for handshake values
+    private static final Random RANDOM_NUMBER_GENERATOR = new SecureRandom();
 
     // Source and sink channels
     private SourceChannel source;
     private SinkChannel sink;
 
-    // Random object for handshake values
-    private static final Random rnd;
-
-    static {
-        byte[] someBytes = new byte[8];
-        boolean resultOK = IOUtil.randomBytes(someBytes);
-        if (resultOK) {
-            rnd = new Random(ByteBuffer.wrap(someBytes).getLong());
-        } else {
-            rnd = new Random();
-        }
-    }
-
     private class Initializer
         implements PrivilegedExceptionAction<Void>
     {
@@ -112,6 +105,10 @@
                 SocketChannel sc2 = null;
 
                 try {
+                    // Create secret with a backing array.
+                    ByteBuffer secret = ByteBuffer.allocate(NUM_SECRET_BYTES);
+                    ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES);
+
                     // Loopback address
                     InetAddress lb = InetAddress.getByName("127.0.0.1");
                     assert(lb.isLoopbackAddress());
@@ -128,18 +125,22 @@
                         // Establish connection (assume connections are eagerly
                         // accepted)
                         sc1 = SocketChannel.open(sa);
-                        ByteBuffer bb = ByteBuffer.allocate(8);
-                        long secret = rnd.nextLong();
-                        bb.putLong(secret).flip();
-                        sc1.write(bb);
+                        RANDOM_NUMBER_GENERATOR.nextBytes(secret.array());
+                        do {
+                            sc1.write(secret);
+                        } while (secret.hasRemaining());
+                        secret.rewind();
 
                         // Get a connection and verify it is legitimate
                         sc2 = ssc.accept();
-                        bb.clear();
-                        sc2.read(bb);
+                        do {
+                            sc2.read(bb);
+                        } while (bb.hasRemaining());
                         bb.rewind();
-                        if (bb.getLong() == secret)
+
+                        if (bb.equals(secret))
                             break;
+
                         sc2.close();
                         sc1.close();
                     }
--- a/jdk/src/java.base/windows/native/libjava/jni_util_md.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/windows/native/libjava/jni_util_md.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2014, 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
--- a/jdk/src/java.base/windows/native/libjli/java_md.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.base/windows/native/libjli/java_md.c	Wed Jul 05 22:00:06 2017 +0200
@@ -1006,10 +1006,11 @@
     // make a copy of the args which will be expanded in java if required.
     nargv = (char **)JLI_MemAlloc(argc * sizeof(char*));
     for (i = 0; i < argc; i++) {
+        jboolean arg_expand;
         j = appArgIdx[i];
-        jboolean arg_expand = (JLI_StrCmp(stdargs[j].arg, strv[i]) == 0)
-                                ? stdargs[j].has_wildcard
-                                : JNI_FALSE;
+        arg_expand = (JLI_StrCmp(stdargs[j].arg, strv[i]) == 0)
+            ? stdargs[j].has_wildcard
+            : JNI_FALSE;
         if (needs_expansion == JNI_FALSE)
             needs_expansion = arg_expand;
 
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp	Wed Jul 05 22:00:06 2017 +0200
@@ -256,7 +256,7 @@
 
     AwtFont* awtFont = NULL;
     jobjectArray compFont = NULL;
-    int cfnum;
+    int cfnum = 0;
 
     try {
         if (env->EnsureLocalCapacity(3) < 0)
@@ -264,7 +264,9 @@
 
         if (IsMultiFont(env, font)) {
             compFont = GetComponentFonts(env, font);
-            cfnum = env->GetArrayLength(compFont);
+            if (compFont != NULL) {
+                cfnum = env->GetArrayLength(compFont);
+            }
         } else {
             compFont = NULL;
             cfnum = 0;
@@ -647,7 +649,9 @@
 
     if (IsMultiFont(env, font)) {
         array = GetComponentFonts(env, font);
-        num = env->GetArrayLength(array);
+        if (array != NULL) {
+            num = env->GetArrayLength(array);
+        }
     } else {
         array = NULL;
         num = 0;
@@ -705,14 +709,16 @@
 
     if (IsMultiFont(env, font)) {
         jobject peer = env->CallObjectMethod(font, AwtFont::peerMID);
-        array =  (jobjectArray)(env->CallObjectMethod(
-        peer, AwtFont::makeConvertedMultiFontStringMID, str));
-        DASSERT(!safe_ExceptionOccurred(env));
+        if (peer != NULL) {
+            array = (jobjectArray)(env->CallObjectMethod(
+            peer, AwtFont::makeConvertedMultiFontStringMID, str));
+            DASSERT(!safe_ExceptionOccurred(env));
 
-        if (array != NULL) {
-            arrayLength = env->GetArrayLength(array);
+            if (array != NULL) {
+                arrayLength = env->GetArrayLength(array);
+            }
+            env->DeleteLocalRef(peer);
         }
-        env->DeleteLocalRef(peer);
     } else {
         array = NULL;
         arrayLength = 0;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.h	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.h	Wed Jul 05 22:00:06 2017 +0200
@@ -230,11 +230,14 @@
     INLINE static jobjectArray GetComponentFonts(JNIEnv *env,
                                                      jobject font) {
       jobject platformFont = env->CallObjectMethod(font, AwtFont::peerMID);
-      jobjectArray result =
-          (jobjectArray)(env->GetObjectField(platformFont,
-                                             AwtFont::componentFontsID));
-      env->DeleteLocalRef(platformFont);
-      return result;
+      if (platformFont != NULL) {
+          jobjectArray result =
+              (jobjectArray)(env->GetObjectField(platformFont,
+                                                 AwtFont::componentFontsID));
+          env->DeleteLocalRef(platformFont);
+          return result;
+      }
+      return NULL;
     }
 
    /*
--- a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncConnection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.nio.ByteBuffer;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLConnection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.Closeable;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferConsumer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferConsumer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferGenerator.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferGenerator.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/CharsetToolkit.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/CharsetToolkit.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.nio.ByteBuffer;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.net.InetSocketAddress;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ContinuationFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ContinuationFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/CookieFilter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/CookieFilter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/DataFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/DataFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ErrorFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ErrorFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ExchangeImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ExchangeImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ExecutorWrapper.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ExecutorWrapper.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.security.AccessControlContext;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/FilterFactory.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/FilterFactory.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/FrameReader.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/FrameReader.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,8 +1,28 @@
 /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.nio.ByteBuffer;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/GoAwayFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/GoAwayFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFilter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFilter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HeaderParser.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderParser.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.util.Iterator;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HeadersFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeadersFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Exchange.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Exchange.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http2Frame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Frame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientBuilderImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientBuilderImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import javax.net.ssl.SSLContext;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.Closeable;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.util.Collections;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.net.URI;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -178,7 +178,7 @@
      */
     RawChannel rawChannel() throws IOException {
         if (rawchan == null) {
-            rawchan = new RawChannel(request.client(), connection);
+            rawchan = new RawChannelImpl(request.client(), connection);
         }
         return rawchan;
     }
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ImmutableHeaders.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ImmutableHeaders.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Log.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.util.Locale;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/OutgoingHeaders.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/OutgoingHeaders.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 /**
--- a/jdk/src/java.httpclient/share/classes/java/net/http/PingFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PingFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/PlainProxyConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainProxyConnection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/PriorityFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PriorityFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/PushPromiseFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PushPromiseFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Queue.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Queue.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,151 +20,43 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.nio.channels.ByteChannel;
-import java.nio.channels.GatheringByteChannel;
-import java.nio.channels.SelectableChannel;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.SocketChannel;
 
-//
-// Used to implement WebSocket. Each RawChannel corresponds to a TCP connection
-// (SocketChannel) but is connected to a Selector and an ExecutorService for
-// invoking the send and receive callbacks. Also includes SSL processing.
-//
-final class RawChannel implements ByteChannel, GatheringByteChannel {
+/*
+ * I/O abstraction used to implement WebSocket.
+ */
+public interface RawChannel {
 
-    private final HttpClientImpl client;
-    private final HttpConnection connection;
+    interface RawEvent {
 
-    private interface RawEvent {
-
-        /**
-         * must return the selector interest op flags OR'd.
+        /*
+         * Must return the selector interest op flags.
          */
         int interestOps();
 
-        /**
-         * called when event occurs.
+        /*
+         * Called when event occurs.
          */
         void handle();
     }
 
-    interface NonBlockingEvent extends RawEvent {
-    }
-
-    RawChannel(HttpClientImpl client, HttpConnection connection)
-                                                throws IOException {
-        this.client = client;
-        this.connection = connection;
-        SocketChannel chan = connection.channel();
-        client.cancelRegistration(chan);
-        chan.configureBlocking(false);
-    }
-
-    SocketChannel socketChannel() {
-        return connection.channel();
-    }
-
-    ByteBuffer getRemaining() {
-        return connection.getRemaining();
-    }
-
-    private class RawAsyncEvent extends AsyncEvent {
-
-        private final RawEvent re;
-
-        RawAsyncEvent(RawEvent re) {
-            super(AsyncEvent.BLOCKING); // BLOCKING & !REPEATING
-            this.re = re;
-        }
-
-        RawAsyncEvent(RawEvent re, int flags) {
-            super(flags);
-            this.re = re;
-        }
-
-        @Override
-        public SelectableChannel channel() {
-            return connection.channel();
-        }
-
-        // must return the selector interest op flags OR'd
-        @Override
-        public int interestOps() {
-            return re.interestOps();
-        }
-
-        // called when event occurs
-        @Override
-        public void handle() {
-            re.handle();
-        }
-
-        @Override
-        public void abort() { }
-    }
-
-    private class NonBlockingRawAsyncEvent extends RawAsyncEvent {
-
-        NonBlockingRawAsyncEvent(RawEvent re) {
-            super(re, 0); // !BLOCKING & !REPEATING
-        }
-    }
-
     /*
      * Register given event whose callback will be called once only.
      * (i.e. register new event for each callback)
      */
-    public void registerEvent(RawEvent event) throws IOException {
-        if (!(event instanceof NonBlockingEvent)) {
-            throw new InternalError();
-        }
-        if ((event.interestOps() & SelectionKey.OP_READ) != 0
-                && connection.buffer.hasRemaining()) {
-            // FIXME: a hack to deal with leftovers from previous reads into an
-            // internal buffer (works in conjunction with change in
-            // java.net.http.PlainHttpConnection.readImpl(java.nio.ByteBuffer)
-            connection.channel().configureBlocking(false);
-            event.handle();
-        } else {
-            client.registerEvent(new NonBlockingRawAsyncEvent(event));
-        }
-    }
+    void registerEvent(RawEvent event) throws IOException;
 
-    @Override
-    public int read(ByteBuffer dst) throws IOException {
-        assert !connection.channel().isBlocking();
-        return connection.read(dst);
-    }
+    int read(ByteBuffer dst) throws IOException;
 
-    @Override
-    public boolean isOpen() {
-        return connection.isOpen();
-    }
-
-    @Override
-    public void close() throws IOException {
-        connection.close();
-    }
+    long write(ByteBuffer[] src, int offset, int len) throws IOException;
 
-    @Override
-    public long write(ByteBuffer[] src) throws IOException {
-        return connection.write(src, 0, src.length);
-    }
+    boolean isOpen();
 
-    @Override
-    public long write(ByteBuffer[] src, int offset, int len)
-            throws IOException {
-        return connection.write(src, offset, len);
-    }
-
-    @Override
-    public int write(ByteBuffer src) throws IOException {
-        return (int) connection.write(src);
-    }
+    void close() throws IOException;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannelImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+
+/*
+ * Each RawChannel corresponds to a TCP connection (SocketChannel) but is
+ * connected to a Selector and an ExecutorService for invoking the send and
+ * receive callbacks. Also includes SSL processing.
+ */
+final class RawChannelImpl implements RawChannel {
+
+    private final HttpClientImpl client;
+    private final HttpConnection connection;
+
+    RawChannelImpl(HttpClientImpl client, HttpConnection connection)
+            throws IOException {
+        this.client = client;
+        this.connection = connection;
+        SocketChannel chan = connection.channel();
+        client.cancelRegistration(chan);
+        chan.configureBlocking(false);
+    }
+
+    private class NonBlockingRawAsyncEvent extends AsyncEvent {
+
+        private final RawEvent re;
+
+        NonBlockingRawAsyncEvent(RawEvent re) {
+            super(0); // !BLOCKING & !REPEATING
+            this.re = re;
+        }
+
+        @Override
+        public SelectableChannel channel() {
+            return connection.channel();
+        }
+
+        @Override
+        public int interestOps() {
+            return re.interestOps();
+        }
+
+        @Override
+        public void handle() {
+            re.handle();
+        }
+
+        @Override
+        public void abort() { }
+    }
+
+    @Override
+    public void registerEvent(RawEvent event) throws IOException {
+        if ((event.interestOps() & SelectionKey.OP_READ) != 0
+                && connection.buffer.hasRemaining()) {
+            // FIXME: a hack to deal with leftovers from previous reads into an
+            // internal buffer (works in conjunction with change in
+            // java.net.http.PlainHttpConnection.readImpl(java.nio.ByteBuffer)
+            connection.channel().configureBlocking(false);
+            event.handle();
+        } else {
+            client.registerEvent(new NonBlockingRawAsyncEvent(event));
+        }
+    }
+
+    @Override
+    public int read(ByteBuffer dst) throws IOException {
+        assert !connection.channel().isBlocking();
+        return connection.read(dst);
+    }
+
+    @Override
+    public long write(ByteBuffer[] src, int offset, int len) throws IOException {
+        return connection.write(src, offset, len);
+    }
+
+    @Override
+    public boolean isOpen() {
+        return connection.isOpen();
+    }
+
+    @Override
+    public void close() throws IOException {
+        connection.close();
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ResetFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResetFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ResponseContent.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseContent.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/SettingsFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SettingsFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
@@ -466,7 +467,7 @@
 
         public synchronized void take(int amount) throws InterruptedException {
             assert permits >= 0;
-            while (permits < amount) {
+            while (amount > 0) {
                 int n = Math.min(amount, permits);
                 permits -= n;
                 amount -= n;
@@ -498,7 +499,7 @@
 
     DataFrame getDataFrame() throws IOException, InterruptedException {
         userRequestFlowController.take();
-        int maxpayloadLen = connection.getMaxSendFrameSize() - 9;
+        int maxpayloadLen = connection.getMaxSendFrameSize();
         ByteBuffer buffer = connection.getBuffer();
         buffer.limit(maxpayloadLen);
         boolean complete = requestProcessor.onRequestBodyChunk(buffer);
--- a/jdk/src/java.httpclient/share/classes/java/net/http/TimeoutEvent.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/TimeoutEvent.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import sun.net.NetProperties;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WS.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WS.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSBuilder.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSBuilder.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.net.URI;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSCharsetToolkit.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSCharsetToolkit.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,7 +20,9 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
+
 package java.net.http;
 
 import java.nio.ByteBuffer;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSDisposable.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSDisposable.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 interface WSDisposable {
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.nio.ByteBuffer;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSFrameConsumer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSFrameConsumer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.net.http.WSFrame.Opcode;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSMessageConsumer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSMessageConsumer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.net.http.WebSocket.CloseCode;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSMessageSender.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSMessageSender.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.net.http.WSFrame.HeaderBuilder;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSOpeningHandshake.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSOpeningHandshake.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.io.UncheckedIOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSOutgoingMessage.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSOutgoingMessage.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.nio.ByteBuffer;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSProtocolException.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSProtocolException.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,3 +1,28 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
 package java.net.http;
 
 import java.net.http.WebSocket.CloseCode;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSReceiver.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSReceiver.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
@@ -53,7 +54,7 @@
     private final Supplier<WSShared<ByteBuffer>> buffersSupplier =
             new WSSharedPool<>(() -> ByteBuffer.allocateDirect(32768), 2);
     private final RawChannel channel;
-    private final RawChannel.NonBlockingEvent channelEvent;
+    private final RawChannel.RawEvent channelEvent;
     private final WSSignalHandler handler;
     private final AtomicLong demand = new AtomicLong();
     private final AtomicBoolean readable = new AtomicBoolean();
@@ -251,8 +252,8 @@
         assert newDemand >= 0 : newDemand;
     }
 
-    private RawChannel.NonBlockingEvent createChannelEvent() {
-        return new RawChannel.NonBlockingEvent() {
+    private RawChannel.RawEvent createChannelEvent() {
+        return new RawChannel.RawEvent() {
 
             @Override
             public int interestOps() {
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSShared.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSShared.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.nio.Buffer;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSSharedPool.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSSharedPool.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,18 +3,18 @@
  * 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  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.nio.Buffer;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSSignalHandler.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSSignalHandler.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.util.concurrent.Executor;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSTransmitter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSTransmitter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.net.http.WSOutgoingMessage.Binary;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSUtils.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSUtils.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.net.URI;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WSWriter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WSWriter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General  License version 2 only, as
+ * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  License
+ * 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  License version
+ * 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.
  *
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
@@ -60,7 +61,7 @@
 final class WSWriter {
 
     private final RawChannel channel;
-    private final RawChannel.NonBlockingEvent writeReadinessHandler;
+    private final RawChannel.RawEvent writeReadinessHandler;
     private final Consumer<Throwable> completionCallback;
     private ByteBuffer[] buffers;
     private int offset;
@@ -110,8 +111,8 @@
         return -1;
     }
 
-    private RawChannel.NonBlockingEvent createHandler() {
-        return new RawChannel.NonBlockingEvent() {
+    private RawChannel.RawEvent createHandler() {
+        return new RawChannel.RawEvent() {
 
             @Override
             public int interestOps() {
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WebSocket.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WebSocket.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 import java.io.IOException;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WebSocketHandshakeException.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WebSocketHandshakeException.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.net.http;
 
 /**
--- a/jdk/src/java.httpclient/share/classes/java/net/http/WindowUpdateFrame.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WindowUpdateFrame.java	Wed Jul 05 22:00:06 2017 +0200
@@ -20,6 +20,7 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
+ * questions.
  */
 
 package java.net.http;
--- a/jdk/src/java.httpclient/share/classes/module-info.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.httpclient/share/classes/module-info.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -38,7 +38,7 @@
  * A transformer of class files. An agent registers an implementation of this
  * interface using the {@link Instrumentation#addTransformer addTransformer}
  * method so that the transformer's {@link
- * ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[])
+ * ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[])
  * transform} method is invoked when classes are loaded,
  * {@link Instrumentation#redefineClasses redefined}, or
  * {@link Instrumentation#retransformClasses retransformed}. The implementation
@@ -170,13 +170,13 @@
     /**
      * Transforms the given class file and returns a new replacement class file.
      * This method is invoked when the {@link Module Module} bearing {@link
-     * ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[])
+     * ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[])
      * transform} is not overridden.
      *
      * @implSpec The default implementation returns null.
      *
      * @param loader                the defining loader of the class to be transformed,
-     *                              may be <code>null</code> if the bootstrap loader
+     *                              may be {@code null} if the bootstrap loader
      * @param className             the name of the class in the internal form of fully
      *                              qualified class and interface names as defined in
      *                              <i>The Java Virtual Machine Specification</i>.
@@ -208,9 +208,11 @@
      *
      * @implSpec The default implementation of this method invokes the
      * {@link #transform(ClassLoader,String,Class,ProtectionDomain,byte[]) transform}
-     * method with the {@link Module#getClassLoader() ClassLoader} for the module.
+     * method.
      *
      * @param module                the module of the class to be transformed
+     * @param loader                the defining loader of the class to be transformed,
+     *                              may be {@code null} if the bootstrap loader
      * @param className             the name of the class in the internal form of fully
      *                              qualified class and interface names as defined in
      *                              <i>The Java Virtual Machine Specification</i>.
@@ -230,15 +232,13 @@
      */
     default byte[]
     transform(  Module              module,
+                ClassLoader         loader,
                 String              className,
                 Class<?>            classBeingRedefined,
                 ProtectionDomain    protectionDomain,
                 byte[]              classfileBuffer)
         throws IllegalClassFormatException {
 
-        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
-        ClassLoader loader = AccessController.doPrivileged(pa);
-
         // invoke the legacy transform method
         return transform(loader,
                          className,
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Wed Jul 05 22:00:06 2017 +0200
@@ -162,7 +162,7 @@
      *    </li>
      *    <li>for each transformer that was added with <code>canRetransform</code>
      *      false, the bytes returned by
-     *      {@link ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[])
+     *      {@link ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[])
      *      transform} during the last class load or redefine are
      *      reused as the output of the transformation; note that this is
      *      equivalent to reapplying the previous transformation, unaltered;
@@ -170,7 +170,7 @@
      *    </li>
      *    <li>for each transformer that was added with <code>canRetransform</code>
      *      true, the
-     *      {@link ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[])
+     *      {@link ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[])
      *      transform} method is called in these transformers
      *    </li>
      *    <li>the transformed class file bytes are installed as the new
--- a/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -420,8 +420,8 @@
 
     // WARNING: the native code knows the name & signature of this method
     private byte[]
-    transform(  ClassLoader         loader,
-                Module              module,
+    transform(  Module              module,
+                ClassLoader         loader,
                 String              classname,
                 Class<?>            classBeingRedefined,
                 ProtectionDomain    protectionDomain,
@@ -444,6 +444,7 @@
             return null; // no manager, no transform
         } else {
             return mgr.transform(   module,
+                                    loader,
                                     classname,
                                     classBeingRedefined,
                                     protectionDomain,
--- a/jdk/src/java.instrument/share/classes/sun/instrument/TransformerManager.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.instrument/share/classes/sun/instrument/TransformerManager.java	Wed Jul 05 22:00:06 2017 +0200
@@ -169,6 +169,7 @@
 
     public byte[]
     transform(  Module              module,
+                ClassLoader         loader,
                 String              classname,
                 Class<?>            classBeingRedefined,
                 ProtectionDomain    protectionDomain,
@@ -187,6 +188,7 @@
 
             try {
                 transformedBytes = transformer.transform(   module,
+                                                            loader,
                                                             classname,
                                                             classBeingRedefined,
                                                             protectionDomain,
--- a/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c	Wed Jul 05 22:00:06 2017 +0200
@@ -771,12 +771,11 @@
 }
 
 static jobject
-getModuleObject(JNIEnv *                jnienv,
+getModuleObject(jvmtiEnv*               jvmti,
                 jobject                 loaderObject,
                 const char*             cname) {
-    jboolean errorOutstanding = JNI_FALSE;
+    jvmtiError err = JVMTI_ERROR_NONE;
     jobject moduleObject = NULL;
-    jstring package = NULL;
 
     /* find last slash in the class name */
     char* last_slash = (cname == NULL) ? NULL : strrchr(cname, '/');
@@ -789,14 +788,9 @@
     }
     pkg_name_buf[len] = '\0';
 
-    package = (*jnienv)->NewStringUTF(jnienv, pkg_name_buf);
-    jplis_assert_msg(package != NULL, "OOM error in NewStringUTF");
+    err = (*jvmti)->GetNamedModule(jvmti, loaderObject, pkg_name_buf, &moduleObject);
+    jplis_assert_msg(err == JVMTI_ERROR_NONE, "error in the JVMTI GetNamedModule");
 
-    moduleObject = JVM_GetModuleByPackageName(jnienv, loaderObject, package);
-
-    errorOutstanding = checkForAndClearThrowable(jnienv);
-    jplis_assert_msg(!errorOutstanding,
-                     "error in lookup of a module of the class being instrumented");
     free((void*)pkg_name_buf);
     return moduleObject;
 }
@@ -862,7 +856,7 @@
             jobject moduleObject = NULL;
 
             if (classBeingRedefined == NULL) {
-                moduleObject = getModuleObject(jnienv, loaderObject, name);
+                moduleObject = getModuleObject(jvmti(agent), loaderObject, name);
             } else {
                 // Redefine or retransform, InstrumentationImpl.transform() will use
                 // classBeingRedefined.getModule() to get the module.
@@ -873,8 +867,8 @@
                                                 jnienv,
                                                 agent->mInstrumentationImpl,
                                                 agent->mTransform,
+                                                moduleObject,
                                                 loaderObject,
-                                                moduleObject,
                                                 classNameStringObject,
                                                 classBeingRedefined,
                                                 protectionDomain,
--- a/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.h	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.h	Wed Jul 05 22:00:06 2017 +0200
@@ -66,7 +66,7 @@
 #define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V"
 #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME           "transform"
 #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE      \
-    "(Ljava/lang/ClassLoader;Ljava/lang/reflect/Module;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B"
+    "(Ljava/lang/reflect/Module;Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B"
 
 
 /*
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/security/JMXSubjectDomainCombiner.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/security/JMXSubjectDomainCombiner.java	Wed Jul 05 22:00:06 2017 +0200
@@ -81,7 +81,7 @@
      * A ProtectionDomain with a null CodeSource and an empty permission set.
      */
     private static final ProtectionDomain pdNoPerms =
-        new ProtectionDomain(nullCodeSource, new Permissions());
+        new ProtectionDomain(nullCodeSource, new Permissions(), null, null);
 
     /**
      * Get the current AccessControlContext combined with the supplied subject.
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
--- a/jdk/src/java.management/share/classes/javax/management/ConstructorParameters.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/java.management/share/classes/javax/management/ConstructorParameters.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/jdk/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 
 package sun.security.ec;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.math.BigInteger;
 
@@ -461,6 +462,11 @@
             DerValue[] values = in.getSequence(2);
             BigInteger r = values[0].getPositiveBigInteger();
             BigInteger s = values[1].getPositiveBigInteger();
+
+            // Check for trailing signature data
+            if (in.available() != 0) {
+                throw new IOException("Incorrect signature length");
+            }
             // trim leading zeroes
             byte[] rBytes = trimZeroes(r.toByteArray());
             byte[] sBytes = trimZeroes(s.toByteArray());
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Signature.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Signature.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -742,6 +742,11 @@
             DerValue[] values = in.getSequence(2);
             BigInteger r = values[0].getPositiveBigInteger();
             BigInteger s = values[1].getPositiveBigInteger();
+
+            // Check for trailing signature data
+            if (in.available() != 0) {
+                throw new IOException("Incorrect signature length");
+            }
             byte[] br = toByteArray(r, 20);
             byte[] bs = toByteArray(s, 20);
             if ((br == null) || (bs == null)) {
@@ -761,6 +766,11 @@
             DerValue[] values = in.getSequence(2);
             BigInteger r = values[0].getPositiveBigInteger();
             BigInteger s = values[1].getPositiveBigInteger();
+
+            // Check for trailing signature data
+            if (in.available() != 0) {
+                throw new IOException("Incorrect signature length");
+            }
             // trim leading zeroes
             byte[] br = KeyUtil.trimZeroes(r.toByteArray());
             byte[] bs = KeyUtil.trimZeroes(s.toByteArray());
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/LibMDMech.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/LibMDMech.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,12 +57,18 @@
 
     private static final int DEFAULT_TAG_LEN = 128; // same as SunJCE provider
 
+    // same as SunJCE provider, see GaloisCounterMode.java for details
+    private static final int MAX_BUF_SIZE = Integer.MAX_VALUE;
+
     // buffer for storing AAD data; if null, meaning buffer content has been
     // supplied to native context
-    private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
+    private ByteArrayOutputStream aadBuffer;
 
     // buffer for storing input in decryption, not used for encryption
-    private ByteArrayOutputStream ibuffer = null;
+    private ByteArrayOutputStream ibuffer;
+
+    // needed for checking against MAX_BUF_SIZE
+    private int processed;
 
     private int tagLen = DEFAULT_TAG_LEN;
 
@@ -75,10 +81,22 @@
      * key + iv values used in previous encryption.
      * For decryption operations, no checking is necessary.
      */
-    private boolean requireReinit = false;
+    private boolean requireReinit;
     private byte[] lastEncKey = null;
     private byte[] lastEncIv = null;
 
+    private void checkAndUpdateProcessed(int len) {
+        // Currently, cipher text and tag are packed in one byte array, so
+        // the impl-specific limit for input data size is (MAX_BUF_SIZE - tagLen)
+        int inputDataLimit = MAX_BUF_SIZE - tagLen;
+
+        if (processed > inputDataLimit - len) {
+            throw new ProviderException("OracleUcrypto provider only supports " +
+                "input size up to " + inputDataLimit + " bytes");
+        }
+        processed += len;
+    }
+
     NativeGCMCipher(int fixedKeySize) throws NoSuchAlgorithmException {
         super(UcryptoMech.CRYPTO_AES_GCM, fixedKeySize);
     }
@@ -86,12 +104,14 @@
     @Override
     protected void ensureInitialized() {
         if (!initialized) {
-            if (aadBuffer != null && aadBuffer.size() > 0) {
-                init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
-                aadBuffer = null;
-            } else {
-                init(encrypt, keyValue, iv, tagLen, null);
+            byte[] aad = null;
+            if (aadBuffer != null) {
+                if (aadBuffer.size() > 0) {
+                    aad = aadBuffer.toByteArray();
+                }
             }
+            init(encrypt, keyValue, iv, tagLen, aad);
+            aadBuffer = null;
             if (!initialized) {
                 throw new UcryptoException("Cannot initialize Cipher");
             }
@@ -136,6 +156,7 @@
             ibuffer.reset();
         }
         if (!encrypt) requireReinit = false;
+        processed = 0;
     }
 
     // actual init() implementation - caller should clone key and iv if needed
@@ -185,6 +206,7 @@
             throw new InvalidAlgorithmParameterException
                 ("Unsupported mode: " + opmode);
         }
+        aadBuffer = new ByteArrayOutputStream();
         boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE);
         byte[] keyBytes = key.getEncoded().clone();
         byte[] ivBytes = null;
@@ -219,6 +241,7 @@
             }
             lastEncIv = ivBytes;
             lastEncKey = keyBytes;
+            ibuffer = null;
         } else {
             requireReinit = false;
             ibuffer = new ByteArrayOutputStream();
@@ -246,15 +269,18 @@
     // see JCE spec
     @Override
     protected synchronized byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
-        if (aadBuffer != null && aadBuffer.size() > 0) {
-            // init again with AAD data
-            init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+        if (aadBuffer != null) {
+            if (aadBuffer.size() > 0) {
+                // init again with AAD data
+                init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+            }
             aadBuffer = null;
         }
         if (requireReinit) {
             throw new IllegalStateException
                 ("Must use either different key or iv for GCM encryption");
         }
+        checkAndUpdateProcessed(inLen);
         if (inLen > 0) {
             if (!encrypt) {
                 ibuffer.write(in, inOfs, inLen);
@@ -274,15 +300,18 @@
                  "(at least) " + len + " bytes long. Got: " +
                  (out.length - outOfs));
         }
-        if (aadBuffer != null && aadBuffer.size() > 0) {
-            // init again with AAD data
-            init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+        if (aadBuffer != null) {
+            if (aadBuffer.size() > 0) {
+                // init again with AAD data
+                init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+            }
             aadBuffer = null;
         }
         if (requireReinit) {
             throw new IllegalStateException
                 ("Must use either different key or iv for GCM encryption");
         }
+        checkAndUpdateProcessed(inLen);
         if (inLen > 0) {
             if (!encrypt) {
                 ibuffer.write(in, inOfs, inLen);
@@ -374,15 +403,19 @@
                 + "(at least) " + len + " bytes long. Got: " +
                 (out.length - outOfs));
         }
-        if (aadBuffer != null && aadBuffer.size() > 0) {
-            // init again with AAD data
-            init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+        if (aadBuffer != null) {
+            if (aadBuffer.size() > 0) {
+                // init again with AAD data
+                init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+            }
             aadBuffer = null;
         }
         if (requireReinit) {
             throw new IllegalStateException
                 ("Must use either different key or iv for GCM encryption");
         }
+
+        checkAndUpdateProcessed(inLen);
         if (!encrypt) {
             if (inLen > 0) {
                 ibuffer.write(in, inOfs, inLen);
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java	Wed Jul 05 22:00:06 2017 +0200
@@ -330,9 +330,9 @@
     protected synchronized boolean engineVerify(byte[] sigBytes, int sigOfs, int sigLen)
         throws SignatureException {
         if (sigBytes == null || (sigOfs < 0) || (sigBytes.length < (sigOfs + this.sigLength))
-            || (sigLen < this.sigLength)) {
-            throw new SignatureException("Invalid signature buffer. sigOfs: " +
-                sigOfs + ". sigLen: " + sigLen + ". this.sigLength: " + this.sigLength);
+            || (sigLen != this.sigLength)) {
+            throw new SignatureException("Invalid signature length: got " +
+                sigLen + " but was expecting " + this.sigLength);
         }
 
         int rv = doFinal(sigBytes, sigOfs, sigLen);
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java	Wed Jul 05 22:00:06 2017 +0200
@@ -39,6 +39,8 @@
 import jdk.internal.jimage.BasicImageReader;
 import jdk.internal.jimage.ImageHeader;
 import jdk.internal.jimage.ImageLocation;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.tree.ClassNode;
 import jdk.tools.jlink.internal.ImageResourcesTree;
 import jdk.tools.jlink.internal.TaskHelper;
 import jdk.tools.jlink.internal.TaskHelper.BadArgs;
@@ -354,16 +356,14 @@
     }
 
       void verify(BasicImageReader reader, String name, ImageLocation location) {
-        if (name.endsWith(".class")) {
-            byte[] bytes = reader.getResource(location);
-
-            if (bytes == null || bytes.length <= 4 ||
-                (bytes[0] & 0xFF) != 0xCA ||
-                (bytes[1] & 0xFF) != 0xFE ||
-                (bytes[2] & 0xFF) != 0xBA ||
-                (bytes[3] & 0xFF) != 0xBE) {
-                log.print(" NOT A CLASS: ");
-                print(reader, name);
+        if (name.endsWith(".class") && !name.endsWith("module-info.class")) {
+            try {
+                byte[] bytes = reader.getResource(location);
+                ClassReader cr =new ClassReader(bytes);
+                ClassNode cn = new ClassNode();
+                cr.accept(cn, ClassReader.EXPAND_FRAMES);
+            } catch (Exception ex) {
+                log.println("Error(s) in Class: " + name);
             }
         }
     }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties	Wed Jul 05 22:00:06 2017 +0200
@@ -63,7 +63,7 @@
 \  --dir                             Target directory for extract directive
 
 main.opt.include=\
-\  --include <pattern-list>          Pattern list for filtering list or extract entries.
+\  --include <pattern-list>          Pattern list for filtering entries.
 
 main.opt.footer=\
 \n\
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -23,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package jdk.tools.jlink.builder;
 
 import java.io.BufferedOutputStream;
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/BasicImageWriter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/BasicImageWriter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -21,7 +21,7 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
-*/
+ */
 
 package jdk.tools.jlink.internal;
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PerfectHashBuilder.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PerfectHashBuilder.java	Wed Jul 05 22:00:06 2017 +0200
@@ -21,7 +21,7 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
-*/
+ */
 
 package jdk.tools.jlink.internal;
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Wed Jul 05 22:00:06 2017 +0200
@@ -24,6 +24,7 @@
  */
 package jdk.tools.jlink.internal.plugins;
 
+import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.IllformedLocaleException;
@@ -31,6 +32,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import static java.util.ResourceBundle.Control;
 import java.util.Set;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
@@ -45,6 +47,10 @@
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.Plugin;
+import sun.util.cldr.CLDRBaseLocaleDataMetaInfo;
+import sun.util.locale.provider.LocaleProviderAdapter;
+import sun.util.locale.provider.LocaleProviderAdapter.Type;
+import sun.util.locale.provider.ResourceBundleBasedAdapter;
 
 /**
  * Plugin to explicitly specify the locale data included in jdk.localedata
@@ -95,6 +101,42 @@
     private List<Locale> available;
     private List<String> filtered;
 
+    private static final ResourceBundleBasedAdapter CLDR_ADAPTER =
+        (ResourceBundleBasedAdapter)LocaleProviderAdapter.forType(Type.CLDR);
+    private static final Map<Locale, String[]> CLDR_PARENT_LOCALES =
+        new CLDRBaseLocaleDataMetaInfo().parentLocales();
+
+    // Equivalent map
+    private static final Map<String, List<String>> EQUIV_MAP =
+        Stream.concat(
+            // COMPAT equivalence
+            Map.of(
+                "zh-Hans", List.of("zh-Hans", "zh-CN", "zh-SG"),
+                "zh-Hant", List.of("zh-Hant", "zh-HK", "zh-MO", "zh-TW"))
+                .entrySet()
+                .stream(),
+
+            // CLDR parent locales
+            CLDR_PARENT_LOCALES.entrySet().stream()
+                .map(entry -> {
+                    String parent = entry.getKey().toLanguageTag();
+                    List<String> children = new ArrayList<>();
+                    children.add(parent);
+
+                    Arrays.stream(entry.getValue())
+                        .filter(child -> !child.isEmpty())
+                        .flatMap(child ->
+                            Stream.concat(
+                                Arrays.stream(CLDR_PARENT_LOCALES.getOrDefault(
+                                    Locale.forLanguageTag(child), new String[0]))
+                                        .filter(grandchild -> !grandchild.isEmpty()),
+                                List.of(child).stream()))
+                        .distinct()
+                        .forEach(children::add);
+                    return new AbstractMap.SimpleEntry<String, List<String>>(parent, children);
+                })
+        ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
     // Special COMPAT provider locales
     private static final String jaJPJPTag = "ja-JP-JP";
     private static final String noNONYTag = "no-NO-NY";
@@ -152,16 +194,14 @@
     @Override
     public void configure(Map<String, String> config) {
         userParam = config.get(NAME);
-        priorityList = Arrays.stream(userParam.split(","))
-            .map(s -> {
-                try {
-                    return new Locale.LanguageRange(s);
-                } catch (IllegalArgumentException iae) {
-                    throw new IllegalArgumentException(String.format(
-                        PluginsResourceBundle.getMessage(NAME + ".invalidtag"), s));
-                }
-            })
-            .collect(Collectors.toList());
+
+        try {
+            priorityList = Locale.LanguageRange.parse(userParam, EQUIV_MAP);
+        } catch (IllegalArgumentException iae) {
+            throw new IllegalArgumentException(String.format(
+                PluginsResourceBundle.getMessage(NAME + ".invalidtag"),
+                    iae.getMessage().replaceFirst("^range=", "")));
+        }
     }
 
     @Override
@@ -193,6 +233,7 @@
             // jdk.localedata is not added.
             throw new PluginException(PluginsResourceBundle.getMessage(NAME + ".localedatanotfound"));
         }
+
         filtered = filterLocales(available);
 
         if (filtered.isEmpty()) {
@@ -205,56 +246,26 @@
                 filtered.stream().flatMap(s -> includeLocaleFilePatterns(s).stream()))
             .map(s -> "regex:" + s)
             .collect(Collectors.toList());
+
         predicate = ResourceFilter.includeFilter(value);
     }
 
     private List<String> includeLocaleFilePatterns(String tag) {
-        List<String> files = new ArrayList<>();
-        String pTag = tag.replaceAll("-", "_");
-        int lastDelimiter = tag.length();
-        String isoSpecial = pTag.matches("^(he|yi|id).*") ?
-                            pTag.replaceFirst("he", "iw")
-                                .replaceFirst("yi", "ji")
-                                .replaceFirst("id", "in") : "";
-
-        // Add tag patterns including parents
-        while (true) {
-            pTag = pTag.substring(0, lastDelimiter);
-            files.addAll(includeLocaleFiles(pTag));
-
-            if (!isoSpecial.isEmpty()) {
-                isoSpecial = isoSpecial.substring(0, lastDelimiter);
-                files.addAll(includeLocaleFiles(isoSpecial));
-            }
-
-            lastDelimiter = pTag.lastIndexOf('_');
-            if (lastDelimiter == -1) {
-                break;
-            }
+        // Ignore extension variations
+        if (tag.matches(".+-[a-z]-.+")) {
+            return List.of();
         }
 
-        final String lang = pTag;
-
-        // Add possible special locales of the COMPAT provider
-        Set.of(jaJPJPTag, noNONYTag, thTHTHTag).stream()
-            .filter(stag -> lang.equals(stag.substring(0,2)))
-            .map(t -> includeLocaleFiles(t.replaceAll("-", "_")))
-            .forEach(files::addAll);
-
-        // Add possible UN.M49 files (unconditional for now) for each language
-        files.addAll(includeLocaleFiles(lang + "_[0-9]{3}"));
-        if (!isoSpecial.isEmpty()) {
-            files.addAll(includeLocaleFiles(isoSpecial + "_[0-9]{3}"));
-        }
+        List<String> files = new ArrayList<>(includeLocaleFiles(tag.replaceAll("-", "_")));
 
         // Add Thai BreakIterator related data files
-        if (lang.equals("th")) {
+        if (tag.equals("th")) {
             files.add(".+sun/text/resources/thai_dict");
             files.add(".+sun/text/resources/[^_]+BreakIteratorData_th");
         }
 
         // Add Taiwan resource bundles for Hong Kong
-        if (tag.startsWith("zh-HK")) {
+        if (tag.equals("zh-HK")) {
             files.addAll(includeLocaleFiles("zh_TW"));
         }
 
@@ -306,6 +317,11 @@
         byte[] filteredBytes = filterLocales(locales).stream()
             .collect(Collectors.joining(" "))
             .getBytes();
+
+        if (filteredBytes.length > b.length) {
+            throw new InternalError("Size of filtered locales is bigger than the original one");
+        }
+
         System.arraycopy(filteredBytes, 0, b, 0, filteredBytes.length);
         Arrays.fill(b, filteredBytes.length, b.length, (byte)' ');
         return true;
@@ -314,6 +330,9 @@
     private List<String> filterLocales(List<Locale> locales) {
         List<String> ret =
             Locale.filter(priorityList, locales, Locale.FilteringMode.EXTENDED_FILTERING).stream()
+                .flatMap(loc -> Stream.concat(Control.getNoFallbackControl(Control.FORMAT_DEFAULT)
+                                     .getCandidateLocales("", loc).stream(),
+                                CLDR_ADAPTER.getCandidateLocales("", loc).stream()))
                 .map(loc ->
                     // Locale.filter() does not preserve the case, which is
                     // significant for "variant" equality. Retrieve the original
@@ -321,15 +340,12 @@
                     locales.stream()
                         .filter(l -> l.toString().equalsIgnoreCase(loc.toString()))
                         .findAny()
-                        .orElse(Locale.ROOT)
-                        .toLanguageTag())
+                        .orElse(Locale.ROOT))
+                .filter(loc -> !loc.equals(Locale.ROOT))
+                .flatMap(IncludeLocalesPlugin::localeToTags)
+                .distinct()
                 .collect(Collectors.toList());
 
-        // no-NO-NY.toLanguageTag() returns "nn-NO", so specially handle it here
-        if (ret.contains("no-NO")) {
-            ret.add(noNONYTag);
-        }
-
         return ret;
     }
 
@@ -338,6 +354,7 @@
         // ISO3166 compatibility
         tag = tag.replaceFirst("^iw", "he").replaceFirst("^ji", "yi").replaceFirst("^in", "id");
 
+        // Special COMPAT provider locales
         switch (tag) {
             case jaJPJPTag:
                 return jaJPJP;
@@ -351,4 +368,42 @@
                 return LOCALE_BUILDER.build();
         }
     }
+
+    private static Stream<String> localeToTags(Locale loc) {
+        String tag = loc.toLanguageTag();
+        Stream<String> ret = null;
+
+        switch (loc.getLanguage()) {
+            // ISO3166 compatibility
+            case "iw":
+                ret = List.of(tag, tag.replaceFirst("^he", "iw")).stream();
+                break;
+            case "in":
+                ret = List.of(tag, tag.replaceFirst("^id", "in")).stream();
+                break;
+            case "ji":
+                ret = List.of(tag, tag.replaceFirst("^yi", "ji")).stream();
+                break;
+
+            // Special COMPAT provider locales
+            case "ja":
+                if (loc.getCountry() == "JP") {
+                    ret = List.of(tag, jaJPJPTag).stream();
+                }
+                break;
+            case "no":
+            case "nn":
+                if (loc.getCountry() == "NO") {
+                    ret = List.of(tag, noNONYTag).stream();
+                }
+                break;
+            case "th":
+                if (loc.getCountry() == "TH") {
+                    ret = List.of(tag, thTHTHTag).stream();
+                }
+                break;
+        }
+
+        return ret == null ? List.of(tag).stream() : ret;
+    }
 }
--- a/jdk/src/sample/share/annotations/DependencyChecker/PluginChecker/src/checker/Device.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/annotations/DependencyChecker/PluginChecker/src/checker/Device.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,3 @@
-package checker;
-
 /*
  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  *
@@ -31,6 +29,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+package checker;
+
 /*
  * This source code is provided to illustrate the usage of a given feature
  * or technique and has been deliberately simplified. Additional steps
--- a/jdk/src/sample/share/annotations/DependencyChecker/PluginChecker/src/checker/Module.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/annotations/DependencyChecker/PluginChecker/src/checker/Module.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,3 @@
-package checker;
-
 /*
  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  *
@@ -31,6 +29,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+package checker;
+
 /*
  * This source code is provided to illustrate the usage of a given feature
  * or technique and has been deliberately simplified. Additional steps
--- a/jdk/src/sample/share/annotations/DependencyChecker/PluginChecker/src/checker/RequireContainer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/annotations/DependencyChecker/PluginChecker/src/checker/RequireContainer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,3 @@
-package checker;
-
 /*
  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  *
@@ -31,6 +29,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+package checker;
+
 /*
  * This source code is provided to illustrate the usage of a given feature
  * or technique and has been deliberately simplified. Additional steps
--- a/jdk/src/sample/share/nio/chatserver/ChatServer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/nio/chatserver/ChatServer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/src/sample/share/nio/chatserver/Client.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/nio/chatserver/Client.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/src/sample/share/nio/chatserver/ClientReader.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/nio/chatserver/ClientReader.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/src/sample/share/nio/chatserver/DataReader.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/nio/chatserver/DataReader.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/src/sample/share/nio/chatserver/MessageReader.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/nio/chatserver/MessageReader.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/src/sample/share/nio/chatserver/NameReader.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/src/sample/share/nio/chatserver/NameReader.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/jdk/test/ProblemList.txt	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 22:00:06 2017 +0200
@@ -138,6 +138,8 @@
 
 java/lang/instrument/BootClassPath/BootClassPathTest.sh         8072130 macosx-all
 
+java/lang/instrument/DaemonThread/TestDaemonThread.java         8161225 generic-all
+
 java/lang/management/MemoryMXBean/LowMemoryTest.java            8130339 generic-all
 
 java/lang/management/MemoryMXBean/Pending.java                  8158837 generic-all
@@ -171,6 +173,8 @@
 
 java/net/DatagramSocket/SendDatagramToBadAddress.java           7143960 macosx-all
 
+java/net/httpclient/SplitResponse.java                          8157533 generic-all 
+
 java/net/httpclient/http2/BasicTest.java                        8157408 linux-all
 java/net/httpclient/http2/ErrorTest.java                        8158127 solaris-all,windows-all
 java/net/httpclient/http2/TLSConnection.java                    8157482 macosx-all
--- a/jdk/test/java/lang/Class/GenericStringTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/Class/GenericStringTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6298888 6992705
+ * @bug 6298888 6992705 8161500
  * @summary Check Class.toGenericString()
  * @author Joseph D. Darcy
  */
@@ -58,15 +58,11 @@
         f = GenericStringTest.class.getDeclaredField("mixed2");
         failures += checkToGenericString(f.getType(), "java.util.Map<K,V>[][]");
 
-        Class<?>[] types = {
-            GenericStringTest.class,
-            AnInterface.class,
-            LocalMap.class,
-            AnEnum.class,
-            AnotherEnum.class,
-        };
-
-        for(Class<?> clazz : types) {
+        for(Class<?> clazz : List.of(GenericStringTest.class,
+                                     AnInterface.class,
+                                     LocalMap.class,
+                                     AnEnum.class,
+                                     AnotherEnum.class)) {
             failures += checkToGenericString(clazz, clazz.getAnnotation(ExpectedGenericString.class).value());
         }
 
--- a/jdk/test/java/lang/ProcessBuilder/Zombies.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/ProcessBuilder/Zombies.java	Wed Jul 05 22:00:06 2017 +0200
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 6474073
+ * @key intermittent
  * @summary Make sure zombies don't get created on Unix
  * @author Martin Buchholz
  */
--- a/jdk/test/java/lang/Runtime/Version/Basic.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/Runtime/Version/Basic.java	Wed Jul 05 22:00:06 2017 +0200
@@ -24,7 +24,7 @@
 /*
  * @test
  * @summary Unit test for java.lang.Runtime.Version.
- * @bug 8072379 8144062
+ * @bug 8072379 8144062 8161236
  */
 
 import java.lang.reflect.InvocationTargetException;
@@ -55,7 +55,7 @@
     public static void main(String ... args) {
 
         //// Tests for parse(), major(), minor(), security(), pre(),
-        //// build(), opt(), version(), toString()
+        //// build(), optional(), version(), toString()
         //   v                          M     m sec pre bld opt
 
         // $VNUM
@@ -119,7 +119,8 @@
         //// Test for Runtime.version()
         testVersion();
 
-        //// Test for equals{IgnoreOpt}?(), hashCode(), compareTo{IgnoreOpt}?()
+        //// Test for equals{IgnoreOptional}?(), hashCode(),
+        //// compareTo{IgnoreOptional}?()
         // compare: after "<" == -1, equal == 0, before ">" == 1
         //      v0            v1                  eq     eqNO  cmp  cmpNO
         testEHC("9",          "9",                true,  true,   0,    0);
@@ -293,9 +294,9 @@
     }
 
     private static void testEqualsNO(Version v0, Version v1, boolean eq) {
-        if ((eq && !v0.equalsIgnoreOpt(v1))
-            || (!eq && v0.equalsIgnoreOpt(v1))) {
-            fail("equalsIgnoreOpt() " + Boolean.toString(eq),
+        if ((eq && !v0.equalsIgnoreOptional(v1))
+            || (!eq && v0.equalsIgnoreOptional(v1))) {
+            fail("equalsIgnoreOptional() " + Boolean.toString(eq),
                  v0.toString(), v1.toString());
         } else {
             pass();
@@ -328,12 +329,12 @@
     private static void testCompareNO(Version v0, Version v1, int compare)
     {
         try {
-            Method m = VERSION.getMethod("compareToIgnoreOpt", VERSION);
+            Method m = VERSION.getMethod("compareToIgnoreOptional", VERSION);
             int cmp = (int) m.invoke(v0, v1);
             checkCompare(v0, v1, compare, cmp);
         } catch (IllegalAccessException | InvocationTargetException |
                  NoSuchMethodException ex) {
-            fail(String.format("compareToIgnoreOpt() invocation: %s",
+            fail(String.format("compareToIgnoreOptional() invocation: %s",
                                ex.getClass()),
                  null);
         }
--- a/jdk/test/java/lang/instrument/ATransformerManagementTestCase.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/instrument/ATransformerManagementTestCase.java	Wed Jul 05 22:00:06 2017 +0200
@@ -302,6 +302,7 @@
         public byte[]
         transform(
             Module module,
+            ClassLoader loader,
             String className,
             Class<?> classBeingRedefined,
             ProtectionDomain    protectionDomain,
@@ -311,6 +312,7 @@
             if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this);
 
             return super.transform(     module,
+                                        loader,
                                         className,
                                         classBeingRedefined,
                                         protectionDomain,
--- a/jdk/test/java/lang/instrument/RetransformAgent.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/instrument/RetransformAgent.java	Wed Jul 05 22:00:06 2017 +0200
@@ -69,6 +69,7 @@
         }
 
         public byte[] transform(Module module,
+                                ClassLoader loader,
                                 String className,
                                 Class<?> classBeingRedefined,
                                 ProtectionDomain    protectionDomain,
--- a/jdk/test/java/lang/instrument/SimpleIdentityTransformer.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/instrument/SimpleIdentityTransformer.java	Wed Jul 05 22:00:06 2017 +0200
@@ -63,6 +63,7 @@
     public byte[]
     transform(
         Module module,
+        ClassLoader loader,
         String className,
         Class<?> classBeingRedefined,
         ProtectionDomain    protectionDomain,
--- a/jdk/test/java/lang/invoke/LoopCombinatorLongSignatureTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/invoke/LoopCombinatorLongSignatureTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -39,6 +39,11 @@
  * If a loop with an excessive amount of clauses is created, so that the number of parameters to the resulting loop
  * handle exceeds the allowed maximum, an IAE must be signalled. The test is run first in LambdaForm interpretation mode
  * and then in default mode, wherein bytecode generation falls back to LFI mode due to excessively long methods.
+ * <p>
+ * By default, the test run only checks whether loop handle construction succeeds and fails. If executing the generated
+ * loops is desired, this should be indicated by setting the {@code java.lang.invoke.LoopCombinatorLongSignatureTest.RUN}
+ * environment variable to {@code true}. This is disabled by default as it considerably increases the time needed to run
+ * the test.
  */
 public class LoopCombinatorLongSignatureTest {
 
@@ -51,13 +56,15 @@
     static final int ARG_LIMIT = 254; // for internal reasons, this is the maximum allowed number of arguments
 
     public static void main(String[] args) {
+        boolean run = Boolean.parseBoolean(
+                System.getProperty("java.lang.invoke.LoopCombinatorLongSignatureTest.RUN", "false"));
         for (int loopArgs = 0; loopArgs < 2; ++loopArgs) {
-            testLongSignature(loopArgs, false);
-            testLongSignature(loopArgs, true);
+            testLongSignature(loopArgs, false, run);
+            testLongSignature(loopArgs, true, run);
         }
     }
 
-    static void testLongSignature(int loopArgs, boolean excessive) {
+    static void testLongSignature(int loopArgs, boolean excessive, boolean run) {
         int nClauses = ARG_LIMIT - loopArgs + (excessive ? 1 : 0);
 
         System.out.print((excessive ? "(EXCESSIVE)" : "(LONG     )") + " arguments: " + loopArgs + ", clauses: " + nClauses + " -> ");
@@ -78,7 +85,7 @@
             MethodHandle loop = MethodHandles.loop(clauses);
             if (excessive) {
                 throw new AssertionError("loop construction should have failed");
-            } else {
+            } else if (run) {
                 int r;
                 if (loopArgs == 0) {
                     r = (int) loop.invoke();
@@ -88,6 +95,8 @@
                     r = (int) loop.invokeWithArguments(args);
                 }
                 System.out.println("SUCCEEDED (OK) -> " + r);
+            } else {
+                System.out.println("SUCCEEDED (OK)");
             }
         } catch (IllegalArgumentException iae) {
             if (excessive) {
--- a/jdk/test/java/lang/reflect/Constructor/GenericStringTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/reflect/Constructor/GenericStringTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 5033583 6316717 6470106
+ * @bug 5033583 6316717 6470106 8161500
  * @summary Check toGenericString() and toString() methods
  * @author Joseph D. Darcy
  */
@@ -35,12 +35,8 @@
 public class GenericStringTest {
     public static void main(String argv[]) throws Exception{
         int failures = 0;
-        List<Class<?>> classList = new LinkedList<Class<?>>();
-        classList.add(TestClass1.class);
-        classList.add(TestClass2.class);
 
-
-        for(Class<?> clazz: classList)
+        for(Class<?> clazz: List.of(TestClass1.class, TestClass2.class))
             for(Constructor<?> ctor: clazz.getDeclaredConstructors()) {
                 ExpectedGenericString egs = ctor.getAnnotation(ExpectedGenericString.class);
                 String actual = ctor.toGenericString();
--- a/jdk/test/java/lang/reflect/Field/GenericStringTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/reflect/Field/GenericStringTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 5033583
+ * @bug 5033583 8161500
  * @summary Check toGenericString() method
  * @author Joseph D. Darcy
  */
@@ -35,12 +35,8 @@
 public class GenericStringTest {
     public static void main(String argv[]) throws Exception {
         int failures = 0;
-        List<Class> classList = new LinkedList<Class>();
-        classList.add(TestClass1.class);
-        classList.add(TestClass2.class);
 
-
-        for(Class clazz: classList)
+        for(Class clazz: List.of(TestClass1.class, TestClass2.class))
             for(Field field: clazz.getDeclaredFields()) {
                 ExpectedString es = field.getAnnotation(ExpectedString.class);
                 String genericString = field.toGenericString();
@@ -61,15 +57,15 @@
 
 class TestClass1 {
     @ExpectedString("int TestClass1.field1")
-        int field1;
+    int field1;
 
     @ExpectedString("private static java.lang.String TestClass1.field2")
-        private static String field2;
+    private static String field2;
 }
 
 class TestClass2<E> {
     @ExpectedString("public E TestClass2.field1")
-        public E field1;
+    public E field1;
 }
 
 @Retention(RetentionPolicy.RUNTIME)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Generics/TestGenericReturnTypeToString.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8054213
+ * @summary Check that toString method works properly for generic return type
+ * obtained via reflection
+ * @run main TestGenericReturnTypeToString
+ */
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Method;
+import java.util.List;
+
+public class TestGenericReturnTypeToString {
+
+    public static void main(String[] args) {
+        boolean hasFailures = false;
+        for (Method method : TestGenericReturnTypeToString.class.getMethods()) {
+            if (method.isAnnotationPresent(ExpectedGenericString.class)) {
+                ExpectedGenericString es = method.getAnnotation
+                        (ExpectedGenericString.class);
+                String result = method.getGenericReturnType().toString();
+                if (!es.value().equals(result)) {
+                    hasFailures = true;
+                    System.err.println("Unexpected result of " +
+                            "getGenericReturnType().toString() " +
+                            " for " + method.getName()
+                            + " expected: " + es.value() + " actual: " + result);
+                }
+            }
+            if (hasFailures) {
+                throw new RuntimeException("Test failed");
+            }
+        }
+    }
+
+    @ExpectedGenericString("TestGenericReturnTypeToString$" +
+          "FirstInnerClassGeneric<Dummy>$SecondInnerClassGeneric<Dummy>")
+    public FirstInnerClassGeneric<Dummy>.SecondInnerClassGeneric<Dummy> foo1() {
+        return null;
+    }
+
+    @ExpectedGenericString("TestGenericReturnTypeToString$" +
+          "FirstInnerClassGeneric<Dummy>$SecondInnerClass")
+    public FirstInnerClassGeneric<Dummy>.SecondInnerClass foo2() {
+        return null;
+    }
+
+    @ExpectedGenericString("TestGenericReturnTypeToString$" +
+          "FirstInnerClass$SecondInnerClassGeneric<Dummy>")
+    public FirstInnerClass.SecondInnerClassGeneric<Dummy> foo3() {
+        return null;
+    }
+
+    @ExpectedGenericString("class TestGenericReturnTypeToString$" +
+          "FirstInnerClass$SecondInnerClass")
+    public FirstInnerClass.SecondInnerClass foo4() {
+        return null;
+    }
+
+    @ExpectedGenericString(
+          "java.util.List<java.lang.String>")
+    public java.util.List<java.lang.String> foo5() {
+        return null;
+    }
+
+    @ExpectedGenericString("interface TestGenericReturnTypeToString$" +
+          "FirstInnerClass$Interface")
+    public FirstInnerClass.Interface foo6() {
+        return null;
+    }
+
+    @ExpectedGenericString("TestGenericReturnTypeToString$" +
+          "FirstInnerClass$InterfaceGeneric<Dummy>")
+    public FirstInnerClass.InterfaceGeneric<Dummy> foo7() {
+        return null;
+    }
+
+    public static class FirstInnerClass {
+
+        public class SecondInnerClassGeneric<T> {
+        }
+
+        public class SecondInnerClass {
+        }
+
+        interface Interface {
+        }
+
+        interface InterfaceGeneric<T> {
+        }
+    }
+
+    public class FirstInnerClassGeneric<T> {
+
+        public class SecondInnerClassGeneric<T> {
+        }
+
+        public class SecondInnerClass {
+        }
+    }
+}
+
+@Retention(RetentionPolicy.RUNTIME)
+@interface ExpectedGenericString {
+    String value();
+}
+
+class Dummy {
+}
--- a/jdk/test/java/lang/reflect/Method/GenericStringTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/lang/reflect/Method/GenericStringTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 5033583 6316717 6470106 8004979
+ * @bug 5033583 6316717 6470106 8004979 8161500
  * @summary Check toGenericString() and toString() methods
  * @author Joseph D. Darcy
  */
@@ -35,14 +35,9 @@
 public class GenericStringTest {
     public static void main(String argv[]) throws Exception {
         int failures = 0;
-        List<Class<?>> classList = new LinkedList<Class<?>>();
-        classList.add(TestClass1.class);
-        classList.add(TestClass2.class);
-        classList.add(Roebling.class);
-        classList.add(TestInterface1.class);
 
-
-        for(Class<?> clazz: classList)
+        for(Class<?> clazz: List.of(TestClass1.class, TestClass2.class,
+                                    Roebling.class, TestInterface1.class))
             for(Method method: clazz.getDeclaredMethods()) {
                 ExpectedGenericString egs = method.getAnnotation(ExpectedGenericString.class);
                 if (egs != null) {
@@ -121,6 +116,30 @@
     @ExpectedGenericString(
    "public void TestClass2.method2() throws F")
     public void method2() throws F {return;}
+
+    @ExpectedGenericString(
+   "public E[] TestClass2.method3()")
+    public E[] method3() {return null;}
+
+    @ExpectedGenericString(
+   "public E[][] TestClass2.method4()")
+    public E[][] method4() {return null;}
+
+    @ExpectedGenericString(
+   "public java.util.List<E[]> TestClass2.method5()")
+    public List<E[]> method5() {return null;}
+
+    @ExpectedGenericString(
+   "public java.util.List<?> TestClass2.method6()")
+    public List<?> method6() {return null;}
+
+    @ExpectedGenericString(
+   "public java.util.List<?>[] TestClass2.method7()")
+    public List<?>[] method7() {return null;}
+
+    @ExpectedGenericString(
+   "public <K,V> java.util.Map<K, V> TestClass2.method8()")
+    public <K, V> Map<K, V> method8() {return null;}
 }
 
 class Roebling implements Comparable<Roebling> {
@@ -157,7 +176,6 @@
     @ExpectedGenericString(
     "public default strictfp double TestInterface1.quux()")
     strictfp default double quux(){return 1.0;}
-
 }
 
 @Retention(RetentionPolicy.RUNTIME)
--- a/jdk/test/java/net/URLPermission/URLPermissionTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/net/URLPermission/URLPermissionTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -26,7 +26,7 @@
 
 /**
  * @test
- * @bug 8010464 8027570 8027687 8029354 8114860 8071660
+ * @bug 8010464 8027570 8027687 8029354 8114860 8071660 8161291
  */
 
 public class URLPermissionTest {
@@ -355,15 +355,16 @@
     };
 
     static Test[] actionsStringTest = {
-        actionstest("", ""),
+        actionstest("", ":"),
+        actionstest(":", ":"),
         actionstest(":X-Bar", ":X-Bar"),
-        actionstest("GET", "GET"),
-        actionstest("get", "GET"),
-        actionstest("GET,POST", "GET,POST"),
-        actionstest("GET,post", "GET,POST"),
-        actionstest("get,post", "GET,POST"),
-        actionstest("get,post,DELETE", "DELETE,GET,POST"),
-        actionstest("GET,POST:", "GET,POST"),
+        actionstest("GET", "GET:"),
+        actionstest("get", "GET:"),
+        actionstest("GET,POST", "GET,POST:"),
+        actionstest("GET,post", "GET,POST:"),
+        actionstest("get,post", "GET,POST:"),
+        actionstest("get,post,DELETE", "DELETE,GET,POST:"),
+        actionstest("GET,POST:", "GET,POST:"),
         actionstest("GET:X-Foo,X-bar", "GET:X-Bar,X-Foo"),
         actionstest("GET,POST,DELETE:X-Bar,X-Foo,X-Bar,Y-Foo", "DELETE,GET,POST:X-Bar,X-Bar,X-Foo,Y-Foo")
     };
--- a/jdk/test/java/net/URLPermission/URLTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/net/URLPermission/URLTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -23,167 +23,194 @@
 
 import java.net.URLPermission;
 /*
- * Run the tests once without security manager and once with
- *
  * @test
  * @bug 8010464
  * @modules jdk.httpserver
- * @key intermittent
  * @library /lib/testlibrary/
  * @build jdk.testlibrary.SimpleSSLContext
- * @run main/othervm/java.security.policy=policy.1 URLTest one
- * @run main/othervm URLTest one
- * @run main/othervm/java.security.policy=policy.2 URLTest two
- * @run main/othervm URLTest two
- * @run main/othervm/java.security.policy=policy.3 URLTest three
- * @run main/othervm URLTest three
+ * @run main/othervm URLTest
+ * @summary check URLPermission with Http(s)URLConnection
  */
 
 import java.net.*;
 import java.io.*;
-import java.util.*;
+import java.security.*;
 import java.util.concurrent.*;
-import java.util.logging.*;
 import com.sun.net.httpserver.*;
 import javax.net.ssl.*;
 import jdk.testlibrary.SimpleSSLContext;
 
 public class URLTest {
-    static boolean failed = false;
+
+    static boolean failed;
 
     public static void main (String[] args) throws Exception {
-        boolean no = false, yes = true;
-
-        if (System.getSecurityManager() == null) {
-            yes = false;
-        }
         createServers();
-        InetSocketAddress addr1 = httpServer.getAddress();
-        int port1 = addr1.getPort();
-        InetSocketAddress addr2 = httpsServer.getAddress();
-        int port2 = addr2.getPort();
-
-          // each of the following cases is run with a different policy file
 
-        switch (args[0]) {
-          case "one":
-            String url1 = "http://127.0.0.1:"+ port1 + "/foo.html";
-            String url2 = "https://127.0.0.1:"+ port2 + "/foo.html";
-            String url3 = "http://127.0.0.1:"+ port1 + "/bar.html";
-            String url4 = "https://127.0.0.1:"+ port2 + "/bar.html";
-
-            // simple positive test. Should succceed
-            test(url1, "GET", "X-Foo", no);
-            test(url1, "GET", "Z-Bar", "X-Foo", no);
-            test(url1, "GET", "X-Foo", "Z-Bar", no);
-            test(url1, "GET", "Z-Bar", no);
-            test(url2, "POST", "X-Fob", no);
-
-            // reverse the methods, should fail
-            test(url1, "POST", "X-Foo", yes);
-            test(url2, "GET", "X-Fob", yes);
+        try {
+            // Verify without a Security Manager
+            test1();
+            test2();
+            test3();
 
-            // different URLs, should fail
-            test(url3, "GET", "X-Foo", yes);
-            test(url4, "POST", "X-Fob", yes);
-            break;
-
-          case "two":
-            url1 = "http://127.0.0.1:"+ port1 + "/foo.html";
-            url2 = "https://127.0.0.1:"+ port2 + "/foo.html";
-            url3 = "http://127.0.0.1:"+ port1 + "/bar.html";
-            url4 = "https://127.0.0.1:"+ port2 + "/bar.html";
+            // Set the security manager. Each test will set its own policy.
+            Policy.setPolicy(new CustomPolicy());
+            System.setSecurityManager(new SecurityManager());
+            System.out.println("\n Security Manager has been set.");
 
-            // simple positive test. Should succceed
-            test(url1, "GET", "X-Foo", no);
-            test(url2, "POST", "X-Fob", no);
-            test(url3, "GET", "X-Foo", no);
-            test(url4, "POST", "X-Fob", no);
-            break;
+            test1();
+            test2();
+            test3();
 
-          case "three":
-            url1 = "http://127.0.0.1:"+ port1 + "/foo.html";
-            url2 = "https://127.0.0.1:"+ port2 + "/a/c/d/e/foo.html";
-            url3 = "http://127.0.0.1:"+ port1 + "/a/b/c";
-            url4 = "https://127.0.0.1:"+ port2 + "/a/b/c";
-
-            test(url1, "GET", "X-Foo", yes);
-            test(url2, "POST", "X-Zxc", no);
-            test(url3, "DELETE", "Y-Foo", no);
-            test(url4, "POST", "Y-Foo", yes);
-            break;
-        }
-        shutdown();
-        if (failed) {
-            throw new RuntimeException("Test failed");
+            if (failed)
+                throw new RuntimeException("Test failed");
+        } finally {
+            shutdown();
         }
     }
 
-    public static void test (
-        String u, String method,
-        String header, boolean exceptionExpected
-    )
-        throws Exception
-    {
-        test(u, method, header, null, exceptionExpected);
+    static void test1() throws IOException {
+        System.out.println("\n--- Test 1 ---");
+
+        boolean expectException = false;
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            expectException = true;
+            Policy.setPolicy(new CustomPolicy(
+                new URLPermission("http://127.0.0.1:"+httpPort+"/foo.html", "GET:X-Foo,Z-Bar"),
+                new URLPermission("https://127.0.0.1:"+httpsPort+"/foo.html", "POST:X-Fob,T-Bar")));
+        }
+
+        String url1 = "http://127.0.0.1:"+httpPort+"/foo.html";
+        String url2 = "https://127.0.0.1:"+httpsPort+"/foo.html";
+        String url3 = "http://127.0.0.1:"+httpPort+"/bar.html";
+        String url4 = "https://127.0.0.1:"+httpsPort+"/bar.html";
+
+        // simple positive test. Should succeed
+        test(url1, "GET", "X-Foo");
+        test(url1, "GET", "Z-Bar", "X-Foo");
+        test(url1, "GET", "X-Foo", "Z-Bar");
+        test(url1, "GET", "Z-Bar");
+        test(url2, "POST", "X-Fob");
+
+        // reverse the methods, should fail
+        test(url1, "POST", "X-Foo", expectException);
+        test(url2, "GET", "X-Fob", expectException);
+
+        // different URLs, should fail
+        test(url3, "GET", "X-Foo", expectException);
+        test(url4, "POST", "X-Fob", expectException);
     }
 
-    public static void test (
-        String u, String method,
-        String header1, String header2, boolean exceptionExpected
-    )
-        throws Exception
+    static void test2() throws IOException {
+        System.out.println("\n--- Test 2 ---");
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            Policy.setPolicy(new CustomPolicy(
+                new URLPermission("http://127.0.0.1:"+httpPort+"/*", "GET:X-Foo"),
+                new URLPermission("https://127.0.0.1:"+httpsPort+"/*", "POST:X-Fob")));
+        }
+
+        String url1 = "http://127.0.0.1:"+httpPort+"/foo.html";
+        String url2 = "https://127.0.0.1:"+httpsPort+"/foo.html";
+        String url3 = "http://127.0.0.1:"+httpPort+"/bar.html";
+        String url4 = "https://127.0.0.1:"+httpsPort+"/bar.html";
+
+        // simple positive test. Should succeed
+        test(url1, "GET", "X-Foo");
+        test(url2, "POST", "X-Fob");
+        test(url3, "GET", "X-Foo");
+        test(url4, "POST", "X-Fob");
+    }
+
+    static void test3() throws IOException {
+        System.out.println("\n--- Test 3 ---");
+
+        boolean expectException = false;
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            expectException = true;
+            Policy.setPolicy(new CustomPolicy(
+                new URLPermission("http://127.0.0.1:"+httpPort+"/a/b/-", "DELETE,GET:X-Foo,Y-Foo"),
+                new URLPermission("https://127.0.0.1:"+httpsPort+"/a/c/-", "POST:*")));
+        }
+
+        String url1 = "http://127.0.0.1:"+httpPort+"/foo.html";
+        String url2 = "https://127.0.0.1:"+httpsPort+"/a/c/d/e/foo.html";
+        String url3 = "http://127.0.0.1:"+httpPort+"/a/b/c";
+        String url4 = "https://127.0.0.1:"+httpsPort+"/a/b/c";
+
+        test(url1, "GET", "X-Foo", expectException);
+        test(url2, "POST", "X-Zxc");
+        test(url3, "DELETE", "Y-Foo");
+        test(url4, "POST", "Y-Foo", expectException);
+    }
+
+    // Convenience methods to simplify previous explicit test scenarios.
+    static void test(String u, String method, String header) throws IOException {
+        test(u, method, header, null, false);
+    }
+
+    static void test(String u, String method, String header, boolean expectException)
+        throws IOException
+    {
+        test(u, method, header, null, expectException);
+    }
+
+    static void test(String u, String method, String header1, String header2)
+        throws IOException
+    {
+        test(u, method, header1, header2, false);
+    }
+
+    static void test(String u,
+                     String method,
+                     String header1,
+                     String header2,
+                     boolean expectException)
+        throws IOException
     {
         URL url = new URL(u);
-        System.out.println ("url=" + u + " method="+method + " header1="+header1
-                +" header2 = " + header2
-                +" exceptionExpected="+exceptionExpected);
+        System.out.println("url=" + u + " method=" + method +
+                           " header1=" + header1 + " header2=" + header2 +
+                           " expectException=" + expectException);
         HttpURLConnection urlc = (HttpURLConnection)url.openConnection();
         if (urlc instanceof HttpsURLConnection) {
             HttpsURLConnection ssl = (HttpsURLConnection)urlc;
-            ssl.setHostnameVerifier(new HostnameVerifier() {
-                public boolean verify(String host, SSLSession sess) {
-                    return true;
-                }
-            });
-            ssl.setSSLSocketFactory (ctx.getSocketFactory());
+            ssl.setHostnameVerifier((host, sess) -> true);
+            ssl.setSSLSocketFactory(ctx.getSocketFactory());
         }
         urlc.setRequestMethod(method);
-        if (header1 != null) {
+        if (header1 != null)
             urlc.addRequestProperty(header1, "foo");
-        }
-        if (header2 != null) {
+        if (header2 != null)
             urlc.addRequestProperty(header2, "bar");
-        }
+
         try {
-            int g = urlc.getResponseCode();
-            if (exceptionExpected) {
+            int code = urlc.getResponseCode();
+            if (expectException) {
                 failed = true;
-                System.out.println ("FAIL");
+                System.out.println("FAIL");
                 return;
             }
-            if (g != 200) {
-                String s = Integer.toString(g);
-                throw new RuntimeException("unexpected response "+ s);
-            }
+            if (code != 200)
+                throw new RuntimeException("Unexpected response " + code);
+
             InputStream is = urlc.getInputStream();
-            int c,count=0;
-            byte[] buf = new byte[1024];
-            while ((c=is.read(buf)) != -1) {
-                count += c;
-            }
+            is.readAllBytes();
             is.close();
         } catch (RuntimeException e) {
-            if (! (e instanceof SecurityException) &&
-                        !(e.getCause() instanceof SecurityException)  ||
-                        !exceptionExpected)
-            {
-                System.out.println ("FAIL");
-                //e.printStackTrace();
+            if (!expectException || !(e.getCause() instanceof SecurityException)) {
+                System.out.println ("FAIL. Unexpected: " + e.getMessage());
+                e.printStackTrace();
                 failed = true;
+                return;
+            } else {
+                System.out.println("Got expected exception: " + e.getMessage());
             }
         }
-        System.out.println ("OK");
+        System.out.println ("PASS");
     }
 
     static HttpServer httpServer;
@@ -191,33 +218,31 @@
     static HttpContext c, cs;
     static ExecutorService e, es;
     static SSLContext ctx;
-
-    // These ports need to be hard-coded until we support port number
-    // ranges in the permission class
-
-    static final int PORT1 = 12567;
-    static final int PORT2 = 12568;
+    static int httpPort;
+    static int httpsPort;
 
     static void createServers() throws Exception {
-        InetSocketAddress addr1 = new InetSocketAddress (PORT1);
-        InetSocketAddress addr2 = new InetSocketAddress (PORT2);
-        httpServer = HttpServer.create (addr1, 0);
-        httpsServer = HttpsServer.create (addr2, 0);
+        InetSocketAddress any = new InetSocketAddress(0);
+        httpServer = HttpServer.create(any, 0);
+        httpsServer = HttpsServer.create(any, 0);
 
-        MyHandler h = new MyHandler();
+        OkHandler h = new OkHandler();
 
-        c = httpServer.createContext ("/", h);
-        cs = httpsServer.createContext ("/", h);
+        c = httpServer.createContext("/", h);
+        cs = httpsServer.createContext("/", h);
         e = Executors.newCachedThreadPool();
         es = Executors.newCachedThreadPool();
-        httpServer.setExecutor (e);
-        httpsServer.setExecutor (es);
+        httpServer.setExecutor(e);
+        httpsServer.setExecutor(es);
 
         ctx = new SimpleSSLContext().get();
         httpsServer.setHttpsConfigurator(new HttpsConfigurator (ctx));
 
         httpServer.start();
         httpsServer.start();
+
+        httpPort = httpServer.getAddress().getPort();
+        httpsPort = httpsServer.getAddress().getPort();
     }
 
     static void shutdown() {
@@ -227,15 +252,38 @@
         es.shutdown();
     }
 
-    static class MyHandler implements HttpHandler {
-
-        MyHandler() {
-        }
-
+    static class OkHandler implements HttpHandler {
         public void handle(HttpExchange x) throws IOException {
             x.sendResponseHeaders(200, -1);
             x.close();
         }
     }
 
+    static class CustomPolicy extends Policy {
+        final PermissionCollection perms = new Permissions();
+        CustomPolicy(Permission... permissions) {
+            java.util.Arrays.stream(permissions).forEach(perms::add);
+
+            // needed for the HTTP(S) server
+            perms.add(new SocketPermission("localhost:1024-", "listen,resolve,accept"));
+            // needed by the test to reset the policy, per testX method
+            perms.add(new SecurityPermission("setPolicy"));
+            // needed to shutdown the ThreadPoolExecutor ( used by the servers )
+            perms.add(new RuntimePermission("modifyThread"));
+            // needed by the client code forHttpsURLConnection.setSSLSocketFactory
+            perms.add(new RuntimePermission("setFactory"));
+        }
+
+        public PermissionCollection getPermissions(ProtectionDomain domain) {
+            return perms;
+        }
+
+        public PermissionCollection getPermissions(CodeSource codesource) {
+            return perms;
+        }
+
+        public boolean implies(ProtectionDomain domain, Permission perm) {
+            return perms.implies(perm);
+        }
+    }
 }
--- a/jdk/test/java/net/URLPermission/policy.1	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-//
-// Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
-// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-//
-// This code is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License version 2 only, as
-// published by the Free Software Foundation.
-//
-// 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.
-//
-
-grant {
-    permission java.net.URLPermission "http://127.0.0.1:12567/foo.html", "GET:X-Foo,Z-Bar";
-    permission java.net.URLPermission "https://127.0.0.1:12568/foo.html", "POST:X-Fob,T-Bar";
-
-    // needed for HttpServer
-    permission "java.net.SocketPermission" "localhost:1024-", "listen,resolve,accept";
-    permission "java.util.PropertyPermission" "test.src", "read";
-    permission java.io.FilePermission "${test.src}/../../../lib/testlibrary/jdk/testlibrary/testkeys", "read";
-
-    //permission "java.util.logging.LoggingPermission" "control";
-    //permission "java.io.FilePermission" "/tmp/-", "read,write";
-    permission "java.lang.RuntimePermission" "modifyThread";
-    permission "java.lang.RuntimePermission" "setFactory";
-    permission "java.util.PropertyPermission" "test.src.path", "read";
-};
-
--- a/jdk/test/java/net/URLPermission/policy.2	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-//
-// Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
-// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-//
-// This code is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License version 2 only, as
-// published by the Free Software Foundation.
-//
-// 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.
-//
-
-grant {
-    permission java.net.URLPermission "http://127.0.0.1:12567/*", "GET:X-Foo";
-    permission java.net.URLPermission "https://127.0.0.1:12568/*", "POST:X-Fob";
-
-    // needed for HttpServer
-    permission "java.net.SocketPermission" "localhost:1024-", "listen,resolve,accept";
-    permission "java.util.PropertyPermission" "test.src", "read";
-    permission java.io.FilePermission "${test.src}/../../../lib/testlibrary/jdk/testlibrary/testkeys", "read";
-
-    //permission "java.util.logging.LoggingPermission" "control";
-    //permission "java.io.FilePermission" "/tmp/-", "read,write";
-    permission "java.lang.RuntimePermission" "modifyThread";
-    permission "java.lang.RuntimePermission" "setFactory";
-    permission "java.util.PropertyPermission" "test.src.path", "read";
-};
-
--- a/jdk/test/java/net/URLPermission/policy.3	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-//
-// Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
-// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-//
-// This code is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License version 2 only, as
-// published by the Free Software Foundation.
-//
-// 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.
-//
-
-grant {
-    permission java.net.URLPermission "http://127.0.0.1:12567/a/b/-", "DELETE,GET:X-Foo,Y-Foo";
-    permission java.net.URLPermission "https://127.0.0.1:12568/a/c/-", "POST:*";
-
-    // needed for HttpServer
-    permission "java.net.SocketPermission" "localhost:1024-", "listen,resolve,accept";
-    permission "java.util.PropertyPermission" "test.src", "read";
-    permission java.io.FilePermission "${test.src}/../../../lib/testlibrary/jdk/testlibrary/testkeys", "read";
-
-    //permission "java.util.logging.LoggingPermission" "control";
-    //permission "java.io.FilePermission" "/tmp/-", "read,write";
-    permission "java.lang.RuntimePermission" "modifyThread";
-    permission "java.lang.RuntimePermission" "setFactory";
-    permission "java.util.PropertyPermission" "test.src.path", "read";
-};
--- a/jdk/test/java/net/httpclient/whitebox/java.httpclient/java/net/http/SelectorTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/net/httpclient/whitebox/java.httpclient/java/net/http/SelectorTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -78,7 +78,7 @@
 
             final RawChannel chan = getARawChannel(port);
 
-            chan.registerEvent(new RawChannel.NonBlockingEvent() {
+            chan.registerEvent(new RawChannel.RawEvent() {
                 @Override
                 public int interestOps() {
                     return SelectionKey.OP_READ;
@@ -95,7 +95,7 @@
                 }
             });
 
-            chan.registerEvent(new RawChannel.NonBlockingEvent() {
+            chan.registerEvent(new RawChannel.RawEvent() {
                 @Override
                 public int interestOps() {
                     return SelectionKey.OP_WRITE;
@@ -111,7 +111,7 @@
                         ByteBuffer bb = ByteBuffer.wrap(TestServer.INPUT);
                         counter.incrementAndGet();
                         try {
-                            chan.write(bb);
+                            chan.write(new ByteBuffer[]{bb}, 0, 1);
                         } catch (IOException e) {
                             throw new UncheckedIOException(e);
                         }
--- a/jdk/test/java/nio/file/WatchService/DeleteInterference.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/nio/file/WatchService/DeleteInterference.java	Wed Jul 05 22:00:06 2017 +0200
@@ -32,6 +32,7 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.nio.file.WatchService;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -49,7 +50,8 @@
      * directory.
      */
     public static void main(String[] args) throws Exception {
-        Path dir = Files.createTempDirectory("DeleteInterference");
+        Path testDir = Paths.get(System.getProperty("test.dir", "."));
+        Path dir = Files.createTempDirectory(testDir, "DeleteInterference");
         ExecutorService pool = Executors.newCachedThreadPool();
         try {
             Future<?> task1 = pool.submit(() -> openAndCloseWatcher(dir));
@@ -58,7 +60,6 @@
             task2.get();
         } finally {
             pool.shutdown();
-            deleteFileTree(dir);
         }
     }
 
--- a/jdk/test/java/nio/file/WatchService/LotsOfCancels.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/nio/file/WatchService/LotsOfCancels.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,11 +27,11 @@
  *    an outstanding I/O operation on directory completes after the
  *    directory has been closed
  */
-
 import java.nio.file.ClosedWatchServiceException;
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.nio.file.WatchKey;
 import java.nio.file.WatchService;
 import static java.nio.file.StandardWatchEventKinds.*;
@@ -50,8 +50,8 @@
         // one to bash on cancel, the other to poll the events
         ExecutorService pool = Executors.newCachedThreadPool();
         try {
-            Path top = Files.createTempDirectory("LotsOfCancels");
-            top.toFile().deleteOnExit();
+            Path testDir = Paths.get(System.getProperty("test.dir", "."));
+            Path top = Files.createTempDirectory(testDir, "LotsOfCancels");
             for (int i=1; i<=16; i++) {
                 Path dir = Files.createDirectory(top.resolve("dir-" + i));
                 WatchService watcher = FileSystems.getDefault().newWatchService();
@@ -114,6 +114,4 @@
             failed = true;
         }
     }
-
 }
-
--- a/jdk/test/java/security/Provider/SecurityProviderModularTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/security/Provider/SecurityProviderModularTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -63,8 +63,7 @@
             "TestSecurityProviderClient.java");
     private static final String C_PKG = "client";
     private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
-    private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR
-            + C_PKG + AUTO + JAR_EXTN;
+    private static final String MCN_JAR_NAME = MODULAR + C_PKG + "N" + JAR_EXTN;
     private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
 
     private static final Path BUILD_DIR = Paths.get(".").resolve("build");
@@ -72,7 +71,7 @@
     private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
     private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve(
             S_PKG + DESCRIPTOR);
-    private static final Path C_BUILD_DIR = COMPILE_DIR.resolve(C_PKG);
+    private static final Path C_BLD_DIR = COMPILE_DIR.resolve(C_PKG);
     private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
     private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
 
@@ -88,8 +87,7 @@
     private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
     private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
     private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
-    private static final Path MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR
-            .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME);
+    private static final Path MCN_JAR = C_ARTIFACTS_DIR.resolve(MCN_JAR_NAME);
 
     private static final String MAIN = C_PKG + ".TestSecurityProviderClient";
     private static final String S_INTERFACE = "java.security.Provider";
@@ -102,8 +100,6 @@
 
     private static final boolean WITH_S_DESCR = true;
     private static final boolean WITHOUT_S_DESCR = false;
-    private static final String CLASS_NOT_FOUND_MSG = "NoClassDefFoundError:"
-            + " provider/TestSecurityProvider";
     private static final String PROVIDER_NOT_FOUND_MSG = "Unable to find Test"
             + " Security Provider";
     private static final String CAN_NOT_ACCESS_MSG = "cannot access class";
@@ -126,10 +122,10 @@
             boolean useCLoader = CLASS_LOADER.equals(mechanism);
             boolean useSLoader = SERVICE_LOADER.equals(mechanism);
             String[] args = new String[]{mechanism};
-            //PARAMETER ORDERS -
-            //client Module Type, Service Module Type,
-            //Service META Descriptor Required,
-            //Expected Failure message, mech used to find the provider
+            // PARAMETER ORDERS -
+            // Client Module Type, Service Module Type,
+            // If Service META Descriptor Required,
+            // Expected Failure message, mechanism used to find the provider
             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
                     WITH_S_DESCR, NO_FAILURE, args));
             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
@@ -138,7 +134,8 @@
                     WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
                             : NO_FAILURE), args));
             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
-                    WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+                    WITHOUT_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
+                            : PROVIDER_NOT_FOUND_MSG), args));
             params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
                     WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
                             : NO_FAILURE), args));
@@ -150,11 +147,12 @@
             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
                     WITH_S_DESCR, NO_FAILURE, args));
             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
-                    WITH_S_DESCR, NO_FAILURE, args));
+                    WITHOUT_S_DESCR, NO_FAILURE, args));
             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
                     WITH_S_DESCR, NO_FAILURE, args));
             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
-                    WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+                    WITHOUT_S_DESCR,
+                    (useCLoader) ? NO_FAILURE : PROVIDER_NOT_FOUND_MSG, args));
             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
                     WITH_S_DESCR, NO_FAILURE, args));
             params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
@@ -168,7 +166,8 @@
             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
                     WITH_S_DESCR, NO_FAILURE, args));
             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
-                    WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+                    WITHOUT_S_DESCR,
+                    (useCLoader) ? NO_FAILURE : PROVIDER_NOT_FOUND_MSG, args));
             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
                     WITH_S_DESCR, NO_FAILURE, args));
             params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
@@ -191,22 +190,23 @@
             done &= CompilerUtils.compile(S_SRC, S_BUILD_DIR);
             done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR);
             done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL);
-            //Generate regular/modular jars with(out) META-INF
-            //Service descriptor
+            // Generate modular/regular jars with(out) META-INF
+            // service descriptor
             generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
             generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR,
                     S_WITH_META_DESCR_BUILD_DIR, false);
             generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
             generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR,
                     S_WITH_META_DESCR_BUILD_DIR, false);
-            //Generate regular/modular(depends on explicit/auto Service)
-            //jars for client
-            done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR, "-cp",
+            // Compile client source codes.
+            done &= CompilerUtils.compile(C_SRC, C_BLD_DIR, "-cp",
                     S_JAR.toFile().getCanonicalPath());
-            generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true);
-            generateJar(false, MODULE_TYPE.EXPLICIT,
-                    MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false);
-            generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false);
+            // Generate modular client jar with explicit dependency
+            generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BLD_DIR, true);
+            // Generate modular client jar without any dependency
+            generateJar(false, MODULE_TYPE.EXPLICIT, MCN_JAR, C_BLD_DIR, false);
+            // Generate regular client jar
+            generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BLD_DIR, false);
             System.out.format("%nArtifacts generated successfully? %s", done);
             if (!done) {
                 throw new RuntimeException("Artifacts generation failed");
@@ -244,10 +244,9 @@
 
         OutputAnalyzer output = null;
         try {
-
-            //For automated/explicit module type copy the corresponding
-            //jars to module base folder, which will be considered as
-            //module base path during execution.
+            // For automated/explicit module types, copy the corresponding
+            // jars to module base folder, which will be considered as
+            // module base path during execution.
             if (!(cModuleType == MODULE_TYPE.UNNAMED
                     && sModuletype == MODULE_TYPE.UNNAMED)) {
                 copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
@@ -262,15 +261,14 @@
             String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
                     sJarPath);
 
-            Map<String, String> VM_ARGS = getVMArgs(sModuletype, args);
+            Map<String, String> vmArgs = getVMArgs(sModuletype,
+                    getModuleName(sModuletype, sJarPath, S_PKG), args);
             output = ProcessTools.executeTestJava(
-                    getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS,
+                    getJavaCommand(cmBasePath, cPath, mName, MAIN, vmArgs,
                             args)).outputTo(System.out).errorTo(System.out);
         } finally {
-            //clean module path so that the modulepath can hold only
-            //the required jars for next run.
+            // Clean module path to hold required jars for next run.
             cleanModuleBasePath(M_BASE_PATH);
-            System.out.println("--------------------------------------------");
         }
         return output;
     }
@@ -297,11 +295,12 @@
                 }
             }
         } else {
+            // Choose corresponding client jar to use dependent module
             if (moduleType == MODULE_TYPE.EXPLICIT) {
                 if (dependsOnServiceModule) {
                     return MC_JAR;
                 } else {
-                    return MC_DEPENDS_ON_AUTO_SERVICE_JAR;
+                    return MCN_JAR;
                 }
             } else {
                 return C_JAR;
@@ -313,13 +312,16 @@
      * VM argument required for the test.
      */
     private Map<String, String> getVMArgs(MODULE_TYPE sModuletype,
-            String... args) throws IOException {
-        final Map<String, String> VM_ARGS = new LinkedHashMap<>();
-        VM_ARGS.put("-Duser.language=", "en");
-        VM_ARGS.put("-Duser.region=", "US");
-        //If mechanism selected to find the provider through
-        //Security.getProvider() then use providerName/ProviderClassName based
-        //on modular/regular provider jar in security configuration file.
+            String addModName, String... args) throws IOException {
+        final Map<String, String> vmArgs = new LinkedHashMap<>();
+        vmArgs.put("-Duser.language=", "en");
+        vmArgs.put("-Duser.region=", "US");
+        if (addModName != null && sModuletype == MODULE_TYPE.AUTO) {
+            vmArgs.put("-addmods ", addModName);
+        }
+        // If mechanism selected to find the provider through
+        // Security.getProvider() then use providerName/ProviderClassName based
+        // on modular/regular provider jar in security configuration file.
         if (args != null && args.length > 0 && SECURITY_PROP.equals(args[0])) {
             if (sModuletype == MODULE_TYPE.UNNAMED) {
                 Files.write(SECURE_PROP_EXTN, ("security.provider.10=" + S_IMPL)
@@ -328,10 +330,10 @@
                 Files.write(SECURE_PROP_EXTN, "security.provider.10=TEST"
                         .getBytes());
             }
-            VM_ARGS.put("-Djava.security.properties=", SECURE_PROP_EXTN.toFile()
+            vmArgs.put("-Djava.security.properties=", SECURE_PROP_EXTN.toFile()
                     .getCanonicalPath());
         }
-        return VM_ARGS;
+        return vmArgs;
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/Signature/SignatureLength.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.*;
+
+/*
+ * @test
+ * @bug 8161571
+ * @summary Reject signatures presented for verification that contain extra
+ *          bytes.
+ * @run main SignatureLength
+ */
+public class SignatureLength {
+
+    public static void main(String[] args) throws Exception {
+        main0("EC", 256, "SHA256withECDSA", "SunEC");
+        main0("RSA", 2048, "SHA256withRSA", "SunRsaSign");
+        main0("DSA", 2048, "SHA256withDSA", "SUN");
+
+        if (System.getProperty("os.name").equals("SunOS")) {
+            main0("EC", 256, "SHA256withECDSA", null);
+            main0("RSA", 2048, "SHA256withRSA", null);
+        }
+    }
+
+    private static void main0(String keyAlgorithm, int keysize,
+            String signatureAlgorithm, String provider) throws Exception {
+        byte[] plaintext = "aaa".getBytes("UTF-8");
+
+        // Generate
+        KeyPairGenerator generator =
+            provider == null ?
+                (KeyPairGenerator) KeyPairGenerator.getInstance(keyAlgorithm) :
+                (KeyPairGenerator) KeyPairGenerator.getInstance(
+                                       keyAlgorithm, provider);
+        generator.initialize(keysize);
+        System.out.println("Generating " + keyAlgorithm + " keypair using " +
+            generator.getProvider().getName() + " JCE provider");
+        KeyPair keypair = generator.generateKeyPair();
+
+        // Sign
+        Signature signer =
+            provider == null ?
+                Signature.getInstance(signatureAlgorithm) :
+                Signature.getInstance(signatureAlgorithm, provider);
+        signer.initSign(keypair.getPrivate());
+        signer.update(plaintext);
+        System.out.println("Signing using " + signer.getProvider().getName() +
+            " JCE provider");
+        byte[] signature = signer.sign();
+
+        // Invalidate
+        System.out.println("Invalidating signature ...");
+        byte[] badSignature = new byte[signature.length + 5];
+        System.arraycopy(signature, 0, badSignature, 0, signature.length);
+        badSignature[signature.length] = 0x01;
+        badSignature[signature.length + 1] = 0x01;
+        badSignature[signature.length + 2] = 0x01;
+        badSignature[signature.length + 3] = 0x01;
+        badSignature[signature.length + 4] = 0x01;
+
+        // Verify
+        Signature verifier =
+            provider == null ?
+                Signature.getInstance(signatureAlgorithm) :
+                Signature.getInstance(signatureAlgorithm, provider);
+        verifier.initVerify(keypair.getPublic());
+        verifier.update(plaintext);
+        System.out.println("Verifying using " +
+            verifier.getProvider().getName() + " JCE provider");
+
+        try {
+            System.out.println("Valid? " + verifier.verify(badSignature));
+            throw new Exception(
+                "ERROR: expected a SignatureException but none was thrown");
+        } catch (SignatureException e) {
+            System.out.println("OK: caught expected exception: " + e);
+        }
+        System.out.println();
+    }
+}
--- a/jdk/test/java/security/modules/ModularTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/security/modules/ModularTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -82,7 +82,7 @@
 
         String testName = new StringJoiner("_").add(cModuleType.toString())
                 .add(sModuletype.toString()).add(
-                        (addMetaDesc) ? "DESCRIPTOR" : "NO_DESCRIPTOR")
+                        (addMetaDesc) ? "WITH_SERVICE" : "NO_SERVICE")
                 .toString();
 
         System.out.format("%nStarting Test case: '%s'", testName);
@@ -165,10 +165,12 @@
         if (moduleType == MODULE_TYPE.EXPLICIT) {
             System.out.format(" %nGenerating ModuleDescriptor object");
             builder = new Builder(moduleName).exports(pkg);
-            if (isService) {
+            if (isService && serviceInterface != null && serviceImpl != null) {
                 builder.provides(serviceInterface, serviceImpl);
             } else {
-                builder.uses(serviceInterface);
+                if (serviceInterface != null) {
+                    builder.uses(serviceInterface);
+                }
                 if (depends) {
                     builder.requires(serviceModuleName);
                 }
@@ -261,7 +263,7 @@
         String jarName = jarPath.toFile().getName();
         return (moduleType == MODULE_TYPE.EXPLICIT) ? mName
                 : ((moduleType == MODULE_TYPE.AUTO) ? jarName.substring(0,
-                                jarName.indexOf(JAR_EXTN)) : "");
+                                jarName.indexOf(JAR_EXTN)) : null);
     }
 
     /**
--- a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java	Wed Jul 05 22:00:06 2017 +0200
@@ -42,6 +42,7 @@
 
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.LinkedTransferQueue;
 import java.util.concurrent.SynchronousQueue;
@@ -50,9 +51,11 @@
 public class PollMemoryLeak {
     public static void main(String[] args) throws InterruptedException {
         final BlockingQueue[] qs = {
+            new LinkedBlockingDeque(10),
             new LinkedBlockingQueue(10),
             new LinkedTransferQueue(),
             new ArrayBlockingQueue(10),
+            new ArrayBlockingQueue(10, true),
             new SynchronousQueue(),
             new SynchronousQueue(true),
         };
--- a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java	Wed Jul 05 22:00:06 2017 +0200
@@ -35,6 +35,7 @@
  * @test
  * @author Doug Lea
  * @bug 8004138
+ * @key intermittent
  * @summary Check if ForkJoinPool table leaks thrown exceptions.
  * @run main/othervm -Xmx8m -Djava.util.concurrent.ForkJoinPool.common.parallelism=4 FJExceptionTableLeak
  */
--- a/jdk/test/java/util/concurrent/tck/Atomic8Test.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/tck/Atomic8Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -179,7 +179,7 @@
      * result of supplied function
      */
     public void testReferenceGetAndUpdate() {
-        AtomicReference<Integer> a = new AtomicReference<Integer>(one);
+        AtomicReference<Integer> a = new AtomicReference<>(one);
         assertEquals(new Integer(1), a.getAndUpdate(Atomic8Test::addInteger17));
         assertEquals(new Integer(18), a.getAndUpdate(Atomic8Test::addInteger17));
         assertEquals(new Integer(35), a.get());
@@ -190,7 +190,7 @@
      * returns result.
      */
     public void testReferenceUpdateAndGet() {
-        AtomicReference<Integer> a = new AtomicReference<Integer>(one);
+        AtomicReference<Integer> a = new AtomicReference<>(one);
         assertEquals(new Integer(18), a.updateAndGet(Atomic8Test::addInteger17));
         assertEquals(new Integer(35), a.updateAndGet(Atomic8Test::addInteger17));
         assertEquals(new Integer(35), a.get());
@@ -201,7 +201,7 @@
      * with supplied function.
      */
     public void testReferenceGetAndAccumulate() {
-        AtomicReference<Integer> a = new AtomicReference<Integer>(one);
+        AtomicReference<Integer> a = new AtomicReference<>(one);
         assertEquals(new Integer(1), a.getAndAccumulate(2, Atomic8Test::sumInteger));
         assertEquals(new Integer(3), a.getAndAccumulate(3, Atomic8Test::sumInteger));
         assertEquals(new Integer(6), a.get());
@@ -212,7 +212,7 @@
      * returns result.
      */
     public void testReferenceAccumulateAndGet() {
-        AtomicReference<Integer> a = new AtomicReference<Integer>(one);
+        AtomicReference<Integer> a = new AtomicReference<>(one);
         assertEquals(new Integer(7), a.accumulateAndGet(6, Atomic8Test::sumInteger));
         assertEquals(new Integer(10), a.accumulateAndGet(3, Atomic8Test::sumInteger));
         assertEquals(new Integer(10), a.get());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicBoolean9Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicBoolean9Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+    public static Test suite() {
+        return new TestSuite(AtomicBoolean9Test.class);
+    }
+
+    /**
+     * getPlain returns the last value set
+     */
+    public void testGetPlainSet() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.getPlain());
+        ai.set(false);
+        assertEquals(false, ai.getPlain());
+        ai.set(true);
+        assertEquals(true, ai.getPlain());
+    }
+
+    /**
+     * getOpaque returns the last value set
+     */
+    public void testGetOpaqueSet() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.getOpaque());
+        ai.set(false);
+        assertEquals(false, ai.getOpaque());
+        ai.set(true);
+        assertEquals(true, ai.getOpaque());
+    }
+
+    /**
+     * getAcquire returns the last value set
+     */
+    public void testGetAcquireSet() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.getAcquire());
+        ai.set(false);
+        assertEquals(false, ai.getAcquire());
+        ai.set(true);
+        assertEquals(true, ai.getAcquire());
+    }
+
+    /**
+     * get returns the last value setPlain
+     */
+    public void testGetSetPlain() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.get());
+        ai.setPlain(false);
+        assertEquals(false, ai.get());
+        ai.setPlain(true);
+        assertEquals(true, ai.get());
+    }
+
+    /**
+     * get returns the last value setOpaque
+     */
+    public void testGetSetOpaque() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.get());
+        ai.setOpaque(false);
+        assertEquals(false, ai.get());
+        ai.setOpaque(true);
+        assertEquals(true, ai.get());
+    }
+
+    /**
+     * get returns the last value setRelease
+     */
+    public void testGetSetRelease() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.get());
+        ai.setRelease(false);
+        assertEquals(false, ai.get());
+        ai.setRelease(true);
+        assertEquals(true, ai.get());
+    }
+
+    /**
+     * compareAndExchange succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchange() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.compareAndExchange(true, false));
+        assertEquals(false, ai.compareAndExchange(false, false));
+        assertEquals(false, ai.get());
+        assertEquals(false, ai.compareAndExchange(true, true));
+        assertEquals(false, ai.get());
+        assertEquals(false, ai.compareAndExchange(false, true));
+        assertEquals(true, ai.get());
+    }
+
+    /**
+     * compareAndExchangeAcquire succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeAcquire() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.compareAndExchangeAcquire(true, false));
+        assertEquals(false, ai.compareAndExchangeAcquire(false, false));
+        assertEquals(false, ai.get());
+        assertEquals(false, ai.compareAndExchangeAcquire(true, true));
+        assertEquals(false, ai.get());
+        assertEquals(false, ai.compareAndExchangeAcquire(false, true));
+        assertEquals(true, ai.get());
+    }
+
+    /**
+     * compareAndExchangeRelease succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeRelease() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        assertEquals(true, ai.compareAndExchangeRelease(true, false));
+        assertEquals(false, ai.compareAndExchangeRelease(false, false));
+        assertEquals(false, ai.get());
+        assertEquals(false, ai.compareAndExchangeRelease(true, true));
+        assertEquals(false, ai.get());
+        assertEquals(false, ai.compareAndExchangeRelease(false, true));
+        assertEquals(true, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetVolatile() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        do {} while (!ai.weakCompareAndSetVolatile(true, false));
+        do {} while (!ai.weakCompareAndSetVolatile(false, false));
+        assertEquals(false, ai.get());
+        do {} while (!ai.weakCompareAndSetVolatile(false, true));
+        assertEquals(true, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetAcquire() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        do {} while (!ai.weakCompareAndSetAcquire(true, false));
+        do {} while (!ai.weakCompareAndSetAcquire(false, false));
+        assertEquals(false, ai.get());
+        do {} while (!ai.weakCompareAndSetAcquire(false, true));
+        assertEquals(true, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetRelease succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetRelease() {
+        AtomicBoolean ai = new AtomicBoolean(true);
+        do {} while (!ai.weakCompareAndSetRelease(true, false));
+        do {} while (!ai.weakCompareAndSetRelease(false, false));
+        assertEquals(false, ai.get());
+        do {} while (!ai.weakCompareAndSetRelease(false, true));
+        assertEquals(true, ai.get());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicInteger9Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicInteger9Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+    public static Test suite() {
+        return new TestSuite(AtomicInteger9Test.class);
+    }
+
+    /**
+     * getPlain returns the last value set
+     */
+    public void testGetPlainSet() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.getPlain());
+        ai.set(2);
+        assertEquals(2, ai.getPlain());
+        ai.set(-3);
+        assertEquals(-3, ai.getPlain());
+    }
+
+    /**
+     * getOpaque returns the last value set
+     */
+    public void testGetOpaqueSet() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.getOpaque());
+        ai.set(2);
+        assertEquals(2, ai.getOpaque());
+        ai.set(-3);
+        assertEquals(-3, ai.getOpaque());
+    }
+
+    /**
+     * getAcquire returns the last value set
+     */
+    public void testGetAcquireSet() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.getAcquire());
+        ai.set(2);
+        assertEquals(2, ai.getAcquire());
+        ai.set(-3);
+        assertEquals(-3, ai.getAcquire());
+    }
+
+    /**
+     * get returns the last value setPlain
+     */
+    public void testGetSetPlain() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.get());
+        ai.setPlain(2);
+        assertEquals(2, ai.get());
+        ai.setPlain(-3);
+        assertEquals(-3, ai.get());
+    }
+
+    /**
+     * get returns the last value setOpaque
+     */
+    public void testGetSetOpaque() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.get());
+        ai.setOpaque(2);
+        assertEquals(2, ai.get());
+        ai.setOpaque(-3);
+        assertEquals(-3, ai.get());
+    }
+
+    /**
+     * get returns the last value setRelease
+     */
+    public void testGetSetRelease() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.get());
+        ai.setRelease(2);
+        assertEquals(2, ai.get());
+        ai.setRelease(-3);
+        assertEquals(-3, ai.get());
+    }
+
+    /**
+     * compareAndExchange succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchange() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.compareAndExchange(1, 2));
+        assertEquals(2, ai.compareAndExchange(2, -4));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchange(-5, 7));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchange(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * compareAndExchangeAcquire succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeAcquire() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.compareAndExchangeAcquire(1, 2));
+        assertEquals(2, ai.compareAndExchangeAcquire(2, -4));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchangeAcquire(-5, 7));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchangeAcquire(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * compareAndExchangeRelease succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeRelease() {
+        AtomicInteger ai = new AtomicInteger(1);
+        assertEquals(1, ai.compareAndExchangeRelease(1, 2));
+        assertEquals(2, ai.compareAndExchangeRelease(2, -4));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchangeRelease(-5, 7));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchangeRelease(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetVolatile() {
+        AtomicInteger ai = new AtomicInteger(1);
+        do {} while (!ai.weakCompareAndSetVolatile(1, 2));
+        do {} while (!ai.weakCompareAndSetVolatile(2, -4));
+        assertEquals(-4, ai.get());
+        do {} while (!ai.weakCompareAndSetVolatile(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetAcquire() {
+        AtomicInteger ai = new AtomicInteger(1);
+        do {} while (!ai.weakCompareAndSetAcquire(1, 2));
+        do {} while (!ai.weakCompareAndSetAcquire(2, -4));
+        assertEquals(-4, ai.get());
+        do {} while (!ai.weakCompareAndSetAcquire(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetRelease succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetRelease() {
+        AtomicInteger ai = new AtomicInteger(1);
+        do {} while (!ai.weakCompareAndSetRelease(1, 2));
+        do {} while (!ai.weakCompareAndSetRelease(2, -4));
+        assertEquals(-4, ai.get());
+        do {} while (!ai.weakCompareAndSetRelease(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicIntegerArray9Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,267 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicIntegerArray9Test extends JSR166TestCase {
+
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+    public static Test suite() {
+        return new TestSuite(AtomicIntegerArray9Test.class);
+    }
+
+    /**
+     * get and set for out of bound indices throw IndexOutOfBoundsException
+     */
+    public void testIndexing() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int index : new int[] { -1, SIZE }) {
+            final int j = index;
+            final Runnable[] tasks = {
+                () -> aa.getPlain(j),
+                () -> aa.getOpaque(j),
+                () -> aa.getAcquire(j),
+                () -> aa.setPlain(j, 1),
+                () -> aa.setOpaque(j, 1),
+                () -> aa.setRelease(j, 1),
+                () -> aa.compareAndExchange(j, 1, 2),
+                () -> aa.compareAndExchangeAcquire(j, 1, 2),
+                () -> aa.compareAndExchangeRelease(j, 1, 2),
+                () -> aa.weakCompareAndSetVolatile(j, 1, 2),
+                () -> aa.weakCompareAndSetAcquire(j, 1, 2),
+                () -> aa.weakCompareAndSetRelease(j, 1, 2),
+            };
+
+            assertThrows(IndexOutOfBoundsException.class, tasks);
+        }
+    }
+
+    /**
+     * getPlain returns the last value set
+     */
+    public void testGetPlainSet() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.getPlain(i));
+            aa.set(i, 2);
+            assertEquals(2, aa.getPlain(i));
+            aa.set(i, -3);
+            assertEquals(-3, aa.getPlain(i));
+        }
+    }
+
+    /**
+     * getOpaque returns the last value set
+     */
+    public void testGetOpaqueSet() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.getOpaque(i));
+            aa.set(i, 2);
+            assertEquals(2, aa.getOpaque(i));
+            aa.set(i, -3);
+            assertEquals(-3, aa.getOpaque(i));
+        }
+    }
+
+    /**
+     * getAcquire returns the last value set
+     */
+    public void testGetAcquireSet() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.getAcquire(i));
+            aa.set(i, 2);
+            assertEquals(2, aa.getAcquire(i));
+            aa.set(i, -3);
+            assertEquals(-3, aa.getAcquire(i));
+        }
+    }
+
+    /**
+     * get returns the last value setPlain
+     */
+    public void testGetSetPlain() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setPlain(i, 1);
+            assertEquals(1, aa.get(i));
+            aa.setPlain(i, 2);
+            assertEquals(2, aa.get(i));
+            aa.setPlain(i, -3);
+            assertEquals(-3, aa.get(i));
+        }
+    }
+
+    /**
+     * get returns the last value setOpaque
+     */
+    public void testGetSetOpaque() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setOpaque(i, 1);
+            assertEquals(1, aa.get(i));
+            aa.setOpaque(i, 2);
+            assertEquals(2, aa.get(i));
+            aa.setOpaque(i, -3);
+            assertEquals(-3, aa.get(i));
+        }
+    }
+
+    /**
+     * get returns the last value setRelease
+     */
+    public void testGetSetRelease() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setRelease(i, 1);
+            assertEquals(1, aa.get(i));
+            aa.setRelease(i, 2);
+            assertEquals(2, aa.get(i));
+            aa.setRelease(i, -3);
+            assertEquals(-3, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchange succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchange() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.compareAndExchange(i, 1, 2));
+            assertEquals(2, aa.compareAndExchange(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchange(i,-5, 7));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchange(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchangeAcquire succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeAcquire() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.compareAndExchangeAcquire(i, 1, 2));
+            assertEquals(2, aa.compareAndExchangeAcquire(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchangeAcquire(i,-5, 7));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchangeAcquire(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchangeRelease succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeRelease() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.compareAndExchangeRelease(i, 1, 2));
+            assertEquals(2, aa.compareAndExchangeRelease(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchangeRelease(i,-5, 7));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchangeRelease(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetVolatile() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            do {} while (!aa.weakCompareAndSetVolatile(i, 1, 2));
+            do {} while (!aa.weakCompareAndSetVolatile(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetVolatile(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetAcquire() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            do {} while (!aa.weakCompareAndSetAcquire(i, 1, 2));
+            do {} while (!aa.weakCompareAndSetAcquire(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetAcquire(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetRelease succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetRelease() {
+        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            do {} while (!aa.weakCompareAndSetRelease(i, 1, 2));
+            do {} while (!aa.weakCompareAndSetRelease(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetRelease(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicLong9Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicLong9Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+    public static Test suite() {
+        return new TestSuite(AtomicLong9Test.class);
+    }
+
+    /**
+     * getPlain returns the last value set
+     */
+    public void testGetPlainSet() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.getPlain());
+        ai.set(2);
+        assertEquals(2, ai.getPlain());
+        ai.set(-3);
+        assertEquals(-3, ai.getPlain());
+    }
+
+    /**
+     * getOpaque returns the last value set
+     */
+    public void testGetOpaqueSet() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.getOpaque());
+        ai.set(2);
+        assertEquals(2, ai.getOpaque());
+        ai.set(-3);
+        assertEquals(-3, ai.getOpaque());
+    }
+
+    /**
+     * getAcquire returns the last value set
+     */
+    public void testGetAcquireSet() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.getAcquire());
+        ai.set(2);
+        assertEquals(2, ai.getAcquire());
+        ai.set(-3);
+        assertEquals(-3, ai.getAcquire());
+    }
+
+    /**
+     * get returns the last value setPlain
+     */
+    public void testGetSetPlain() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.get());
+        ai.setPlain(2);
+        assertEquals(2, ai.get());
+        ai.setPlain(-3);
+        assertEquals(-3, ai.get());
+    }
+
+    /**
+     * get returns the last value setOpaque
+     */
+    public void testGetSetOpaque() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.get());
+        ai.setOpaque(2);
+        assertEquals(2, ai.get());
+        ai.setOpaque(-3);
+        assertEquals(-3, ai.get());
+    }
+
+    /**
+     * get returns the last value setRelease
+     */
+    public void testGetSetRelease() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.get());
+        ai.setRelease(2);
+        assertEquals(2, ai.get());
+        ai.setRelease(-3);
+        assertEquals(-3, ai.get());
+    }
+
+    /**
+     * compareAndExchange succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchange() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.compareAndExchange(1, 2));
+        assertEquals(2, ai.compareAndExchange(2, -4));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchange(-5, 7));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchange(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * compareAndExchangeAcquire succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeAcquire() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.compareAndExchangeAcquire(1, 2));
+        assertEquals(2, ai.compareAndExchangeAcquire(2, -4));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchangeAcquire(-5, 7));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchangeAcquire(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * compareAndExchangeRelease succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeRelease() {
+        AtomicLong ai = new AtomicLong(1);
+        assertEquals(1, ai.compareAndExchangeRelease(1, 2));
+        assertEquals(2, ai.compareAndExchangeRelease(2, -4));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchangeRelease(-5, 7));
+        assertEquals(-4, ai.get());
+        assertEquals(-4, ai.compareAndExchangeRelease(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetVolatile() {
+        AtomicLong ai = new AtomicLong(1);
+        do {} while (!ai.weakCompareAndSetVolatile(1, 2));
+        do {} while (!ai.weakCompareAndSetVolatile(2, -4));
+        assertEquals(-4, ai.get());
+        do {} while (!ai.weakCompareAndSetVolatile(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetAcquire() {
+        AtomicLong ai = new AtomicLong(1);
+        do {} while (!ai.weakCompareAndSetAcquire(1, 2));
+        do {} while (!ai.weakCompareAndSetAcquire(2, -4));
+        assertEquals(-4, ai.get());
+        do {} while (!ai.weakCompareAndSetAcquire(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetRelease succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetRelease() {
+        AtomicLong ai = new AtomicLong(1);
+        do {} while (!ai.weakCompareAndSetRelease(1, 2));
+        do {} while (!ai.weakCompareAndSetRelease(2, -4));
+        assertEquals(-4, ai.get());
+        do {} while (!ai.weakCompareAndSetRelease(-4, 7));
+        assertEquals(7, ai.get());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicLongArray9Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,266 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicLongArray;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicLongArray9Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+    public static Test suite() {
+        return new TestSuite(AtomicLongArray9Test.class);
+    }
+
+    /**
+     * get and set for out of bound indices throw IndexOutOfBoundsException
+     */
+    public void testIndexing() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int index : new int[] { -1, SIZE }) {
+            final int j = index;
+            final Runnable[] tasks = {
+                () -> aa.getPlain(j),
+                () -> aa.getOpaque(j),
+                () -> aa.getAcquire(j),
+                () -> aa.setPlain(j, 1),
+                () -> aa.setOpaque(j, 1),
+                () -> aa.setRelease(j, 1),
+                () -> aa.compareAndExchange(j, 1, 2),
+                () -> aa.compareAndExchangeAcquire(j, 1, 2),
+                () -> aa.compareAndExchangeRelease(j, 1, 2),
+                () -> aa.weakCompareAndSetVolatile(j, 1, 2),
+                () -> aa.weakCompareAndSetAcquire(j, 1, 2),
+                () -> aa.weakCompareAndSetRelease(j, 1, 2),
+            };
+
+            assertThrows(IndexOutOfBoundsException.class, tasks);
+        }
+    }
+
+    /**
+     * getPlain returns the last value set
+     */
+    public void testGetPlainSet() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.getPlain(i));
+            aa.set(i, 2);
+            assertEquals(2, aa.getPlain(i));
+            aa.set(i, -3);
+            assertEquals(-3, aa.getPlain(i));
+        }
+    }
+
+    /**
+     * getOpaque returns the last value set
+     */
+    public void testGetOpaqueSet() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.getOpaque(i));
+            aa.set(i, 2);
+            assertEquals(2, aa.getOpaque(i));
+            aa.set(i, -3);
+            assertEquals(-3, aa.getOpaque(i));
+        }
+    }
+
+    /**
+     * getAcquire returns the last value set
+     */
+    public void testGetAcquireSet() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.getAcquire(i));
+            aa.set(i, 2);
+            assertEquals(2, aa.getAcquire(i));
+            aa.set(i, -3);
+            assertEquals(-3, aa.getAcquire(i));
+        }
+    }
+
+    /**
+     * get returns the last value setPlain
+     */
+    public void testGetSetPlain() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setPlain(i, 1);
+            assertEquals(1, aa.get(i));
+            aa.setPlain(i, 2);
+            assertEquals(2, aa.get(i));
+            aa.setPlain(i, -3);
+            assertEquals(-3, aa.get(i));
+        }
+    }
+
+    /**
+     * get returns the last value setOpaque
+     */
+    public void testGetSetOpaque() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setOpaque(i, 1);
+            assertEquals(1, aa.get(i));
+            aa.setOpaque(i, 2);
+            assertEquals(2, aa.get(i));
+            aa.setOpaque(i, -3);
+            assertEquals(-3, aa.get(i));
+        }
+    }
+
+    /**
+     * get returns the last value setRelease
+     */
+    public void testGetSetRelease() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setRelease(i, 1);
+            assertEquals(1, aa.get(i));
+            aa.setRelease(i, 2);
+            assertEquals(2, aa.get(i));
+            aa.setRelease(i, -3);
+            assertEquals(-3, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchange succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchange() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.compareAndExchange(i, 1, 2));
+            assertEquals(2, aa.compareAndExchange(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchange(i,-5, 7));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchange(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchangeAcquire succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeAcquire() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.compareAndExchangeAcquire(i, 1, 2));
+            assertEquals(2, aa.compareAndExchangeAcquire(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchangeAcquire(i,-5, 7));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchangeAcquire(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchangeRelease succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeRelease() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            assertEquals(1, aa.compareAndExchangeRelease(i, 1, 2));
+            assertEquals(2, aa.compareAndExchangeRelease(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchangeRelease(i,-5, 7));
+            assertEquals(-4, aa.get(i));
+            assertEquals(-4, aa.compareAndExchangeRelease(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetVolatile() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            do {} while (!aa.weakCompareAndSetVolatile(i, 1, 2));
+            do {} while (!aa.weakCompareAndSetVolatile(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetVolatile(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetAcquire() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            do {} while (!aa.weakCompareAndSetAcquire(i, 1, 2));
+            do {} while (!aa.weakCompareAndSetAcquire(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetAcquire(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetRelease succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetRelease() {
+        AtomicLongArray aa = new AtomicLongArray(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, 1);
+            do {} while (!aa.weakCompareAndSetRelease(i, 1, 2));
+            do {} while (!aa.weakCompareAndSetRelease(i, 2, -4));
+            assertEquals(-4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetRelease(i, -4, 7));
+            assertEquals(7, aa.get(i));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicReference9Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicReference9Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+    public static Test suite() {
+        return new TestSuite(AtomicReference9Test.class);
+    }
+
+    /**
+     * getPlain returns the last value set
+     */
+    public void testGetPlainSet() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.getPlain());
+        ai.set(two);
+        assertEquals(two, ai.getPlain());
+        ai.set(m3);
+        assertEquals(m3, ai.getPlain());
+    }
+
+    /**
+     * getOpaque returns the last value set
+     */
+    public void testGetOpaqueSet() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.getOpaque());
+        ai.set(two);
+        assertEquals(two, ai.getOpaque());
+        ai.set(m3);
+        assertEquals(m3, ai.getOpaque());
+    }
+
+    /**
+     * getAcquire returns the last value set
+     */
+    public void testGetAcquireSet() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.getAcquire());
+        ai.set(two);
+        assertEquals(two, ai.getAcquire());
+        ai.set(m3);
+        assertEquals(m3, ai.getAcquire());
+    }
+
+    /**
+     * get returns the last value setPlain
+     */
+    public void testGetSetPlain() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.get());
+        ai.setPlain(two);
+        assertEquals(two, ai.get());
+        ai.setPlain(m3);
+        assertEquals(m3, ai.get());
+    }
+
+    /**
+     * get returns the last value setOpaque
+     */
+    public void testGetSetOpaque() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.get());
+        ai.setOpaque(two);
+        assertEquals(two, ai.get());
+        ai.setOpaque(m3);
+        assertEquals(m3, ai.get());
+    }
+
+    /**
+     * get returns the last value setRelease
+     */
+    public void testGetSetRelease() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.get());
+        ai.setRelease(two);
+        assertEquals(two, ai.get());
+        ai.setRelease(m3);
+        assertEquals(m3, ai.get());
+    }
+
+    /**
+     * compareAndExchange succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchange() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.compareAndExchange(one, two));
+        assertEquals(two, ai.compareAndExchange(two, m4));
+        assertEquals(m4, ai.get());
+        assertEquals(m4, ai.compareAndExchange(m5, seven));
+        assertEquals(m4, ai.get());
+        assertEquals(m4, ai.compareAndExchange(m4, seven));
+        assertEquals(seven, ai.get());
+    }
+
+    /**
+     * compareAndExchangeAcquire succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeAcquire() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.compareAndExchangeAcquire(one, two));
+        assertEquals(two, ai.compareAndExchangeAcquire(two, m4));
+        assertEquals(m4, ai.get());
+        assertEquals(m4, ai.compareAndExchangeAcquire(m5, seven));
+        assertEquals(m4, ai.get());
+        assertEquals(m4, ai.compareAndExchangeAcquire(m4, seven));
+        assertEquals(seven, ai.get());
+    }
+
+    /**
+     * compareAndExchangeRelease succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeRelease() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        assertEquals(one, ai.compareAndExchangeRelease(one, two));
+        assertEquals(two, ai.compareAndExchangeRelease(two, m4));
+        assertEquals(m4, ai.get());
+        assertEquals(m4, ai.compareAndExchangeRelease(m5, seven));
+        assertEquals(m4, ai.get());
+        assertEquals(m4, ai.compareAndExchangeRelease(m4, seven));
+        assertEquals(seven, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetVolatile() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        do {} while (!ai.weakCompareAndSetVolatile(one, two));
+        do {} while (!ai.weakCompareAndSetVolatile(two, m4));
+        assertEquals(m4, ai.get());
+        do {} while (!ai.weakCompareAndSetVolatile(m4, seven));
+        assertEquals(seven, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetAcquire() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        do {} while (!ai.weakCompareAndSetAcquire(one, two));
+        do {} while (!ai.weakCompareAndSetAcquire(two, m4));
+        assertEquals(m4, ai.get());
+        do {} while (!ai.weakCompareAndSetAcquire(m4, seven));
+        assertEquals(seven, ai.get());
+    }
+
+    /**
+     * repeated weakCompareAndSetRelease succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetRelease() {
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
+        do {} while (!ai.weakCompareAndSetRelease(one, two));
+        do {} while (!ai.weakCompareAndSetRelease(two, m4));
+        assertEquals(m4, ai.get());
+        do {} while (!ai.weakCompareAndSetRelease(m4, seven));
+        assertEquals(seven, ai.get());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceArray9Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,266 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicReferenceArray9Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+    public static Test suite() {
+        return new TestSuite(AtomicReferenceArray9Test.class);
+    }
+
+    /**
+     * get and set for out of bound indices throw IndexOutOfBoundsException
+     */
+    public void testIndexing() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int index : new int[] { -1, SIZE }) {
+            final int j = index;
+            final Runnable[] tasks = {
+                () -> aa.getPlain(j),
+                () -> aa.getOpaque(j),
+                () -> aa.getAcquire(j),
+                () -> aa.setPlain(j, null),
+                () -> aa.setOpaque(j, null),
+                () -> aa.setRelease(j, null),
+                () -> aa.compareAndExchange(j, null, null),
+                () -> aa.compareAndExchangeAcquire(j, null, null),
+                () -> aa.compareAndExchangeRelease(j, null, null),
+                () -> aa.weakCompareAndSetVolatile(j, null, null),
+                () -> aa.weakCompareAndSetAcquire(j, null, null),
+                () -> aa.weakCompareAndSetRelease(j, null, null),
+            };
+
+            assertThrows(IndexOutOfBoundsException.class, tasks);
+        }
+    }
+
+    /**
+     * getPlain returns the last value set
+     */
+    public void testGetPlainSet() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            assertEquals(one, aa.getPlain(i));
+            aa.set(i, two);
+            assertEquals(two, aa.getPlain(i));
+            aa.set(i, m3);
+            assertEquals(m3, aa.getPlain(i));
+        }
+    }
+
+    /**
+     * getOpaque returns the last value set
+     */
+    public void testGetOpaqueSet() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            assertEquals(one, aa.getOpaque(i));
+            aa.set(i, two);
+            assertEquals(two, aa.getOpaque(i));
+            aa.set(i, m3);
+            assertEquals(m3, aa.getOpaque(i));
+        }
+    }
+
+    /**
+     * getAcquire returns the last value set
+     */
+    public void testGetAcquireSet() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            assertEquals(one, aa.getAcquire(i));
+            aa.set(i, two);
+            assertEquals(two, aa.getAcquire(i));
+            aa.set(i, m3);
+            assertEquals(m3, aa.getAcquire(i));
+        }
+    }
+
+    /**
+     * get returns the last value setPlain
+     */
+    public void testGetSetPlain() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setPlain(i, one);
+            assertEquals(one, aa.get(i));
+            aa.setPlain(i, two);
+            assertEquals(two, aa.get(i));
+            aa.setPlain(i, m3);
+            assertEquals(m3, aa.get(i));
+        }
+    }
+
+    /**
+     * get returns the last value setOpaque
+     */
+    public void testGetSetOpaque() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setOpaque(i, one);
+            assertEquals(one, aa.get(i));
+            aa.setOpaque(i, two);
+            assertEquals(two, aa.get(i));
+            aa.setOpaque(i, m3);
+            assertEquals(m3, aa.get(i));
+        }
+    }
+
+    /**
+     * get returns the last value setRelease
+     */
+    public void testGetSetRelease() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.setRelease(i, one);
+            assertEquals(one, aa.get(i));
+            aa.setRelease(i, two);
+            assertEquals(two, aa.get(i));
+            aa.setRelease(i, m3);
+            assertEquals(m3, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchange succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchange() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            assertEquals(one, aa.compareAndExchange(i, one, two));
+            assertEquals(two, aa.compareAndExchange(i, two, m4));
+            assertEquals(m4, aa.get(i));
+            assertEquals(m4, aa.compareAndExchange(i,m5, seven));
+            assertEquals(m4, aa.get(i));
+            assertEquals(m4, aa.compareAndExchange(i, m4, seven));
+            assertEquals(seven, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchangeAcquire succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeAcquire() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            assertEquals(one, aa.compareAndExchangeAcquire(i, one, two));
+            assertEquals(two, aa.compareAndExchangeAcquire(i, two, m4));
+            assertEquals(m4, aa.get(i));
+            assertEquals(m4, aa.compareAndExchangeAcquire(i,m5, seven));
+            assertEquals(m4, aa.get(i));
+            assertEquals(m4, aa.compareAndExchangeAcquire(i, m4, seven));
+            assertEquals(seven, aa.get(i));
+        }
+    }
+
+    /**
+     * compareAndExchangeRelease succeeds in changing value if equal to
+     * expected else fails
+     */
+    public void testCompareAndExchangeRelease() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            assertEquals(one, aa.compareAndExchangeRelease(i, one, two));
+            assertEquals(two, aa.compareAndExchangeRelease(i, two, m4));
+            assertEquals(m4, aa.get(i));
+            assertEquals(m4, aa.compareAndExchangeRelease(i,m5, seven));
+            assertEquals(m4, aa.get(i));
+            assertEquals(m4, aa.compareAndExchangeRelease(i, m4, seven));
+            assertEquals(seven, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetVolatile() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            do {} while (!aa.weakCompareAndSetVolatile(i, one, two));
+            do {} while (!aa.weakCompareAndSetVolatile(i, two, m4));
+            assertEquals(m4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetVolatile(i, m4, seven));
+            assertEquals(seven, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetAcquire() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            do {} while (!aa.weakCompareAndSetAcquire(i, one, two));
+            do {} while (!aa.weakCompareAndSetAcquire(i, two, m4));
+            assertEquals(m4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetAcquire(i, m4, seven));
+            assertEquals(seven, aa.get(i));
+        }
+    }
+
+    /**
+     * repeated weakCompareAndSetRelease succeeds in changing value when equal
+     * to expected
+     */
+    public void testWeakCompareAndSetRelease() {
+        AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+        for (int i = 0; i < SIZE; i++) {
+            aa.set(i, one);
+            do {} while (!aa.weakCompareAndSetRelease(i, one, two));
+            do {} while (!aa.weakCompareAndSetRelease(i, two, m4));
+            assertEquals(m4, aa.get(i));
+            do {} while (!aa.weakCompareAndSetRelease(i, m4, seven));
+            assertEquals(seven, aa.get(i));
+        }
+    }
+
+}
--- a/jdk/test/java/util/concurrent/tck/AtomicReferenceArrayTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceArrayTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -243,4 +243,5 @@
         AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(a);
         assertEquals(Arrays.toString(a), aa.toString());
     }
+
 }
--- a/jdk/test/java/util/concurrent/tck/AtomicReferenceTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -161,7 +161,7 @@
      * toString returns current value.
      */
     public void testToString() {
-        AtomicReference<Integer> ai = new AtomicReference<Integer>(one);
+        AtomicReference<Integer> ai = new AtomicReference<>(one);
         assertEquals(one.toString(), ai.toString());
         ai.set(two);
         assertEquals(two.toString(), ai.toString());
--- a/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -57,6 +57,7 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -486,62 +487,68 @@
     class FailingSupplier extends CheckedAction
         implements Supplier<Integer>
     {
-        FailingSupplier(ExecutionMode m) { super(m); }
+        final CFException ex;
+        FailingSupplier(ExecutionMode m) { super(m); ex = new CFException(); }
         public Integer get() {
             invoked();
-            throw new CFException();
+            throw ex;
         }
     }
 
     class FailingConsumer extends CheckedIntegerAction
         implements Consumer<Integer>
     {
-        FailingConsumer(ExecutionMode m) { super(m); }
+        final CFException ex;
+        FailingConsumer(ExecutionMode m) { super(m); ex = new CFException(); }
         public void accept(Integer x) {
             invoked();
             value = x;
-            throw new CFException();
+            throw ex;
         }
     }
 
     class FailingBiConsumer extends CheckedIntegerAction
         implements BiConsumer<Integer, Integer>
     {
-        FailingBiConsumer(ExecutionMode m) { super(m); }
+        final CFException ex;
+        FailingBiConsumer(ExecutionMode m) { super(m); ex = new CFException(); }
         public void accept(Integer x, Integer y) {
             invoked();
             value = subtract(x, y);
-            throw new CFException();
+            throw ex;
         }
     }
 
     class FailingFunction extends CheckedIntegerAction
         implements Function<Integer, Integer>
     {
-        FailingFunction(ExecutionMode m) { super(m); }
+        final CFException ex;
+        FailingFunction(ExecutionMode m) { super(m); ex = new CFException(); }
         public Integer apply(Integer x) {
             invoked();
             value = x;
-            throw new CFException();
+            throw ex;
         }
     }
 
     class FailingBiFunction extends CheckedIntegerAction
         implements BiFunction<Integer, Integer, Integer>
     {
-        FailingBiFunction(ExecutionMode m) { super(m); }
+        final CFException ex;
+        FailingBiFunction(ExecutionMode m) { super(m); ex = new CFException(); }
         public Integer apply(Integer x, Integer y) {
             invoked();
             value = subtract(x, y);
-            throw new CFException();
+            throw ex;
         }
     }
 
     class FailingRunnable extends CheckedAction implements Runnable {
-        FailingRunnable(ExecutionMode m) { super(m); }
+        final CFException ex;
+        FailingRunnable(ExecutionMode m) { super(m); ex = new CFException(); }
         public void run() {
             invoked();
-            throw new CFException();
+            throw ex;
         }
     }
 
@@ -561,11 +568,21 @@
     class FailingCompletableFutureFunction extends CheckedIntegerAction
         implements Function<Integer, CompletableFuture<Integer>>
     {
-        FailingCompletableFutureFunction(ExecutionMode m) { super(m); }
+        final CFException ex;
+        FailingCompletableFutureFunction(ExecutionMode m) { super(m); ex = new CFException(); }
         public CompletableFuture<Integer> apply(Integer x) {
             invoked();
             value = x;
-            throw new CFException();
+            throw ex;
+        }
+    }
+
+    static class CountingRejectingExecutor implements Executor {
+        final RejectedExecutionException ex = new RejectedExecutionException();
+        final AtomicInteger count = new AtomicInteger(0);
+        public void execute(Runnable r) {
+            count.getAndIncrement();
+            throw ex;
         }
     }
 
@@ -1249,10 +1266,22 @@
     {
         final FailingRunnable r = new FailingRunnable(m);
         final CompletableFuture<Void> f = m.runAsync(r);
-        checkCompletedWithWrappedCFException(f);
+        checkCompletedWithWrappedException(f, r.ex);
         r.assertInvoked();
     }}
 
+    public void testRunAsync_rejectingExecutor() {
+        CountingRejectingExecutor e = new CountingRejectingExecutor();
+        try {
+            CompletableFuture.runAsync(() -> {}, e);
+            shouldThrow();
+        } catch (Throwable t) {
+            assertSame(e.ex, t);
+        }
+
+        assertEquals(1, e.count.get());
+    }
+
     /**
      * supplyAsync completes with result of supplier
      */
@@ -1283,10 +1312,22 @@
     {
         FailingSupplier r = new FailingSupplier(m);
         CompletableFuture<Integer> f = m.supplyAsync(r);
-        checkCompletedWithWrappedCFException(f);
+        checkCompletedWithWrappedException(f, r.ex);
         r.assertInvoked();
     }}
 
+    public void testSupplyAsync_rejectingExecutor() {
+        CountingRejectingExecutor e = new CountingRejectingExecutor();
+        try {
+            CompletableFuture.supplyAsync(() -> null, e);
+            shouldThrow();
+        } catch (Throwable t) {
+            assertSame(e.ex, t);
+        }
+
+        assertEquals(1, e.count.get());
+    }
+
     // seq completion methods
 
     /**
@@ -1405,12 +1446,12 @@
         final CompletableFuture<Void> h4 = m.runAfterBoth(f, f, rs[4]);
         final CompletableFuture<Void> h5 = m.runAfterEither(f, f, rs[5]);
 
-        checkCompletedWithWrappedCFException(h0);
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
-        checkCompletedWithWrappedCFException(h4);
-        checkCompletedWithWrappedCFException(h5);
+        checkCompletedWithWrappedException(h0, rs[0].ex);
+        checkCompletedWithWrappedException(h1, rs[1].ex);
+        checkCompletedWithWrappedException(h2, rs[2].ex);
+        checkCompletedWithWrappedException(h3, rs[3].ex);
+        checkCompletedWithWrappedException(h4, rs[4].ex);
+        checkCompletedWithWrappedException(h5, rs[5].ex);
         checkCompletedNormally(f, v1);
     }}
 
@@ -1509,10 +1550,10 @@
         final CompletableFuture<Integer> h2 = m.thenApply(f, rs[2]);
         final CompletableFuture<Integer> h3 = m.applyToEither(f, f, rs[3]);
 
-        checkCompletedWithWrappedCFException(h0);
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
+        checkCompletedWithWrappedException(h0, rs[0].ex);
+        checkCompletedWithWrappedException(h1, rs[1].ex);
+        checkCompletedWithWrappedException(h2, rs[2].ex);
+        checkCompletedWithWrappedException(h3, rs[3].ex);
         checkCompletedNormally(f, v1);
     }}
 
@@ -1611,10 +1652,10 @@
         final CompletableFuture<Void> h2 = m.thenAccept(f, rs[2]);
         final CompletableFuture<Void> h3 = m.acceptEither(f, f, rs[3]);
 
-        checkCompletedWithWrappedCFException(h0);
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
+        checkCompletedWithWrappedException(h0, rs[0].ex);
+        checkCompletedWithWrappedException(h1, rs[1].ex);
+        checkCompletedWithWrappedException(h2, rs[2].ex);
+        checkCompletedWithWrappedException(h3, rs[3].ex);
         checkCompletedNormally(f, v1);
     }}
 
@@ -1776,9 +1817,9 @@
         assertTrue(snd.complete(w2));
         final CompletableFuture<Integer> h3 = m.thenCombine(f, g, r3);
 
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
+        checkCompletedWithWrappedException(h1, r1.ex);
+        checkCompletedWithWrappedException(h2, r2.ex);
+        checkCompletedWithWrappedException(h3, r3.ex);
         r1.assertInvoked();
         r2.assertInvoked();
         r3.assertInvoked();
@@ -1940,9 +1981,9 @@
         assertTrue(snd.complete(w2));
         final CompletableFuture<Void> h3 = m.thenAcceptBoth(f, g, r3);
 
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
+        checkCompletedWithWrappedException(h1, r1.ex);
+        checkCompletedWithWrappedException(h2, r2.ex);
+        checkCompletedWithWrappedException(h3, r3.ex);
         r1.assertInvoked();
         r2.assertInvoked();
         r3.assertInvoked();
@@ -2104,9 +2145,9 @@
         assertTrue(snd.complete(w2));
         final CompletableFuture<Void> h3 = m.runAfterBoth(f, g, r3);
 
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
+        checkCompletedWithWrappedException(h1, r1.ex);
+        checkCompletedWithWrappedException(h2, r2.ex);
+        checkCompletedWithWrappedException(h3, r3.ex);
         r1.assertInvoked();
         r2.assertInvoked();
         r3.assertInvoked();
@@ -2396,10 +2437,10 @@
         f.complete(v1);
         final CompletableFuture<Integer> h2 = m.applyToEither(f, g, rs[2]);
         final CompletableFuture<Integer> h3 = m.applyToEither(g, f, rs[3]);
-        checkCompletedWithWrappedCFException(h0);
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
+        checkCompletedWithWrappedException(h0, rs[0].ex);
+        checkCompletedWithWrappedException(h1, rs[1].ex);
+        checkCompletedWithWrappedException(h2, rs[2].ex);
+        checkCompletedWithWrappedException(h3, rs[3].ex);
         for (int i = 0; i < 4; i++) rs[i].assertValue(v1);
 
         g.complete(v2);
@@ -2408,10 +2449,10 @@
         final CompletableFuture<Integer> h4 = m.applyToEither(f, g, rs[4]);
         final CompletableFuture<Integer> h5 = m.applyToEither(g, f, rs[5]);
 
-        checkCompletedWithWrappedCFException(h4);
+        checkCompletedWithWrappedException(h4, rs[4].ex);
         assertTrue(Objects.equals(v1, rs[4].value) ||
                    Objects.equals(v2, rs[4].value));
-        checkCompletedWithWrappedCFException(h5);
+        checkCompletedWithWrappedException(h5, rs[5].ex);
         assertTrue(Objects.equals(v1, rs[5].value) ||
                    Objects.equals(v2, rs[5].value));
 
@@ -2655,10 +2696,10 @@
         f.complete(v1);
         final CompletableFuture<Void> h2 = m.acceptEither(f, g, rs[2]);
         final CompletableFuture<Void> h3 = m.acceptEither(g, f, rs[3]);
-        checkCompletedWithWrappedCFException(h0);
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
+        checkCompletedWithWrappedException(h0, rs[0].ex);
+        checkCompletedWithWrappedException(h1, rs[1].ex);
+        checkCompletedWithWrappedException(h2, rs[2].ex);
+        checkCompletedWithWrappedException(h3, rs[3].ex);
         for (int i = 0; i < 4; i++) rs[i].assertValue(v1);
 
         g.complete(v2);
@@ -2667,10 +2708,10 @@
         final CompletableFuture<Void> h4 = m.acceptEither(f, g, rs[4]);
         final CompletableFuture<Void> h5 = m.acceptEither(g, f, rs[5]);
 
-        checkCompletedWithWrappedCFException(h4);
+        checkCompletedWithWrappedException(h4, rs[4].ex);
         assertTrue(Objects.equals(v1, rs[4].value) ||
                    Objects.equals(v2, rs[4].value));
-        checkCompletedWithWrappedCFException(h5);
+        checkCompletedWithWrappedException(h5, rs[5].ex);
         assertTrue(Objects.equals(v1, rs[5].value) ||
                    Objects.equals(v2, rs[5].value));
 
@@ -2686,6 +2727,7 @@
         for (ExecutionMode m : ExecutionMode.values())
         for (Integer v1 : new Integer[] { 1, null })
         for (Integer v2 : new Integer[] { 2, null })
+        for (boolean pushNop : new boolean[] { true, false })
     {
         final CompletableFuture<Integer> f = new CompletableFuture<>();
         final CompletableFuture<Integer> g = new CompletableFuture<>();
@@ -2698,6 +2740,10 @@
         checkIncomplete(h1);
         rs[0].assertNotInvoked();
         rs[1].assertNotInvoked();
+        if (pushNop) {          // ad hoc test of intra-completion interference
+            m.thenRun(f, () -> {});
+            m.thenRun(g, () -> {});
+        }
         f.complete(v1);
         checkCompletedNormally(h0, null);
         checkCompletedNormally(h1, null);
@@ -2910,16 +2956,16 @@
         assertTrue(f.complete(v1));
         final CompletableFuture<Void> h2 = m.runAfterEither(f, g, rs[2]);
         final CompletableFuture<Void> h3 = m.runAfterEither(g, f, rs[3]);
-        checkCompletedWithWrappedCFException(h0);
-        checkCompletedWithWrappedCFException(h1);
-        checkCompletedWithWrappedCFException(h2);
-        checkCompletedWithWrappedCFException(h3);
+        checkCompletedWithWrappedException(h0, rs[0].ex);
+        checkCompletedWithWrappedException(h1, rs[1].ex);
+        checkCompletedWithWrappedException(h2, rs[2].ex);
+        checkCompletedWithWrappedException(h3, rs[3].ex);
         for (int i = 0; i < 4; i++) rs[i].assertInvoked();
         assertTrue(g.complete(v2));
         final CompletableFuture<Void> h4 = m.runAfterEither(f, g, rs[4]);
         final CompletableFuture<Void> h5 = m.runAfterEither(g, f, rs[5]);
-        checkCompletedWithWrappedCFException(h4);
-        checkCompletedWithWrappedCFException(h5);
+        checkCompletedWithWrappedException(h4, rs[4].ex);
+        checkCompletedWithWrappedException(h5, rs[5].ex);
 
         checkCompletedNormally(f, v1);
         checkCompletedNormally(g, v2);
@@ -2980,7 +3026,7 @@
         final CompletableFuture<Integer> g = m.thenCompose(f, r);
         if (createIncomplete) assertTrue(f.complete(v1));
 
-        checkCompletedWithWrappedCFException(g);
+        checkCompletedWithWrappedException(g, r.ex);
         checkCompletedNormally(f, v1);
     }}
 
@@ -3089,7 +3135,7 @@
         }
     }
 
-    public void testAllOf_backwards() throws Exception {
+    public void testAllOf_normal_backwards() throws Exception {
         for (int k = 1; k < 10; k++) {
             CompletableFuture<Integer>[] fs
                 = (CompletableFuture<Integer>[]) new CompletableFuture[k];
@@ -3337,6 +3383,151 @@
     }
 
     /**
+     * Test submissions to an executor that rejects all tasks.
+     */
+    public void testRejectingExecutor() {
+        for (Integer v : new Integer[] { 1, null })
+    {
+        final CountingRejectingExecutor e = new CountingRejectingExecutor();
+
+        final CompletableFuture<Integer> complete = CompletableFuture.completedFuture(v);
+        final CompletableFuture<Integer> incomplete = new CompletableFuture<>();
+
+        List<CompletableFuture<?>> futures = new ArrayList<>();
+
+        List<CompletableFuture<Integer>> srcs = new ArrayList<>();
+        srcs.add(complete);
+        srcs.add(incomplete);
+
+        for (CompletableFuture<Integer> src : srcs) {
+            List<CompletableFuture<?>> fs = new ArrayList<>();
+            fs.add(src.thenRunAsync(() -> {}, e));
+            fs.add(src.thenAcceptAsync((z) -> {}, e));
+            fs.add(src.thenApplyAsync((z) -> z, e));
+
+            fs.add(src.thenCombineAsync(src, (x, y) -> x, e));
+            fs.add(src.thenAcceptBothAsync(src, (x, y) -> {}, e));
+            fs.add(src.runAfterBothAsync(src, () -> {}, e));
+
+            fs.add(src.applyToEitherAsync(src, (z) -> z, e));
+            fs.add(src.acceptEitherAsync(src, (z) -> {}, e));
+            fs.add(src.runAfterEitherAsync(src, () -> {}, e));
+
+            fs.add(src.thenComposeAsync((z) -> null, e));
+            fs.add(src.whenCompleteAsync((z, t) -> {}, e));
+            fs.add(src.handleAsync((z, t) -> null, e));
+
+            for (CompletableFuture<?> future : fs) {
+                if (src.isDone())
+                    checkCompletedWithWrappedException(future, e.ex);
+                else
+                    checkIncomplete(future);
+            }
+            futures.addAll(fs);
+        }
+
+        {
+            List<CompletableFuture<?>> fs = new ArrayList<>();
+
+            fs.add(complete.thenCombineAsync(incomplete, (x, y) -> x, e));
+            fs.add(incomplete.thenCombineAsync(complete, (x, y) -> x, e));
+
+            fs.add(complete.thenAcceptBothAsync(incomplete, (x, y) -> {}, e));
+            fs.add(incomplete.thenAcceptBothAsync(complete, (x, y) -> {}, e));
+
+            fs.add(complete.runAfterBothAsync(incomplete, () -> {}, e));
+            fs.add(incomplete.runAfterBothAsync(complete, () -> {}, e));
+
+            for (CompletableFuture<?> future : fs)
+                checkIncomplete(future);
+            futures.addAll(fs);
+        }
+
+        {
+            List<CompletableFuture<?>> fs = new ArrayList<>();
+
+            fs.add(complete.applyToEitherAsync(incomplete, (z) -> z, e));
+            fs.add(incomplete.applyToEitherAsync(complete, (z) -> z, e));
+
+            fs.add(complete.acceptEitherAsync(incomplete, (z) -> {}, e));
+            fs.add(incomplete.acceptEitherAsync(complete, (z) -> {}, e));
+
+            fs.add(complete.runAfterEitherAsync(incomplete, () -> {}, e));
+            fs.add(incomplete.runAfterEitherAsync(complete, () -> {}, e));
+
+            for (CompletableFuture<?> future : fs)
+                checkCompletedWithWrappedException(future, e.ex);
+            futures.addAll(fs);
+        }
+
+        incomplete.complete(v);
+
+        for (CompletableFuture<?> future : futures)
+            checkCompletedWithWrappedException(future, e.ex);
+
+        assertEquals(futures.size(), e.count.get());
+    }}
+
+    /**
+     * Test submissions to an executor that rejects all tasks, but
+     * should never be invoked because the dependent future is
+     * explicitly completed.
+     */
+    public void testRejectingExecutorNeverInvoked() {
+        for (Integer v : new Integer[] { 1, null })
+    {
+        final CountingRejectingExecutor e = new CountingRejectingExecutor();
+
+        final CompletableFuture<Integer> complete = CompletableFuture.completedFuture(v);
+        final CompletableFuture<Integer> incomplete = new CompletableFuture<>();
+
+        List<CompletableFuture<?>> futures = new ArrayList<>();
+
+        List<CompletableFuture<Integer>> srcs = new ArrayList<>();
+        srcs.add(complete);
+        srcs.add(incomplete);
+
+        List<CompletableFuture<?>> fs = new ArrayList<>();
+        fs.add(incomplete.thenRunAsync(() -> {}, e));
+        fs.add(incomplete.thenAcceptAsync((z) -> {}, e));
+        fs.add(incomplete.thenApplyAsync((z) -> z, e));
+
+        fs.add(incomplete.thenCombineAsync(incomplete, (x, y) -> x, e));
+        fs.add(incomplete.thenAcceptBothAsync(incomplete, (x, y) -> {}, e));
+        fs.add(incomplete.runAfterBothAsync(incomplete, () -> {}, e));
+
+        fs.add(incomplete.applyToEitherAsync(incomplete, (z) -> z, e));
+        fs.add(incomplete.acceptEitherAsync(incomplete, (z) -> {}, e));
+        fs.add(incomplete.runAfterEitherAsync(incomplete, () -> {}, e));
+
+        fs.add(incomplete.thenComposeAsync((z) -> null, e));
+        fs.add(incomplete.whenCompleteAsync((z, t) -> {}, e));
+        fs.add(incomplete.handleAsync((z, t) -> null, e));
+
+        fs.add(complete.thenCombineAsync(incomplete, (x, y) -> x, e));
+        fs.add(incomplete.thenCombineAsync(complete, (x, y) -> x, e));
+
+        fs.add(complete.thenAcceptBothAsync(incomplete, (x, y) -> {}, e));
+        fs.add(incomplete.thenAcceptBothAsync(complete, (x, y) -> {}, e));
+
+        fs.add(complete.runAfterBothAsync(incomplete, () -> {}, e));
+        fs.add(incomplete.runAfterBothAsync(complete, () -> {}, e));
+
+        for (CompletableFuture<?> future : fs)
+            checkIncomplete(future);
+
+        for (CompletableFuture<?> future : fs)
+            future.complete(null);
+
+        incomplete.complete(v);
+
+        for (CompletableFuture<?> future : fs)
+            checkCompletedNormally(future, null);
+
+        assertEquals(0, e.count.get());
+    }}
+
+    /**
      * toCompletableFuture returns this CompletableFuture.
      */
     public void testToCompletableFuture() {
@@ -3659,12 +3850,25 @@
     //--- tests of implementation details; not part of official tck ---
 
     Object resultOf(CompletableFuture<?> f) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            try {
+                System.setSecurityManager(null);
+            } catch (SecurityException giveUp) {
+                return "Reflection not available";
+            }
+        }
+
         try {
             java.lang.reflect.Field resultField
                 = CompletableFuture.class.getDeclaredField("result");
             resultField.setAccessible(true);
             return resultField.get(f);
-        } catch (Throwable t) { throw new AssertionError(t); }
+        } catch (Throwable t) {
+            throw new AssertionError(t);
+        } finally {
+            if (sm != null) System.setSecurityManager(sm);
+        }
     }
 
     public void testExceptionPropagationReusesResultObject() {
@@ -3675,33 +3879,44 @@
         final CompletableFuture<Integer> v42 = CompletableFuture.completedFuture(42);
         final CompletableFuture<Integer> incomplete = new CompletableFuture<>();
 
+        final Runnable noopRunnable = new Noop(m);
+        final Consumer<Integer> noopConsumer = new NoopConsumer(m);
+        final Function<Integer, Integer> incFunction = new IncFunction(m);
+
         List<Function<CompletableFuture<Integer>, CompletableFuture<?>>> funs
             = new ArrayList<>();
 
-        funs.add((y) -> m.thenRun(y, new Noop(m)));
-        funs.add((y) -> m.thenAccept(y, new NoopConsumer(m)));
-        funs.add((y) -> m.thenApply(y, new IncFunction(m)));
-
-        funs.add((y) -> m.runAfterEither(y, incomplete, new Noop(m)));
-        funs.add((y) -> m.acceptEither(y, incomplete, new NoopConsumer(m)));
-        funs.add((y) -> m.applyToEither(y, incomplete, new IncFunction(m)));
-
-        funs.add((y) -> m.runAfterBoth(y, v42, new Noop(m)));
+        funs.add((y) -> m.thenRun(y, noopRunnable));
+        funs.add((y) -> m.thenAccept(y, noopConsumer));
+        funs.add((y) -> m.thenApply(y, incFunction));
+
+        funs.add((y) -> m.runAfterEither(y, incomplete, noopRunnable));
+        funs.add((y) -> m.acceptEither(y, incomplete, noopConsumer));
+        funs.add((y) -> m.applyToEither(y, incomplete, incFunction));
+
+        funs.add((y) -> m.runAfterBoth(y, v42, noopRunnable));
+        funs.add((y) -> m.runAfterBoth(v42, y, noopRunnable));
         funs.add((y) -> m.thenAcceptBoth(y, v42, new SubtractAction(m)));
+        funs.add((y) -> m.thenAcceptBoth(v42, y, new SubtractAction(m)));
         funs.add((y) -> m.thenCombine(y, v42, new SubtractFunction(m)));
+        funs.add((y) -> m.thenCombine(v42, y, new SubtractFunction(m)));
 
         funs.add((y) -> m.whenComplete(y, (Integer r, Throwable t) -> {}));
 
         funs.add((y) -> m.thenCompose(y, new CompletableFutureInc(m)));
 
-        funs.add((y) -> CompletableFuture.allOf(new CompletableFuture<?>[] {y, v42}));
-        funs.add((y) -> CompletableFuture.anyOf(new CompletableFuture<?>[] {y, incomplete}));
+        funs.add((y) -> CompletableFuture.allOf(y));
+        funs.add((y) -> CompletableFuture.allOf(y, v42));
+        funs.add((y) -> CompletableFuture.allOf(v42, y));
+        funs.add((y) -> CompletableFuture.anyOf(y));
+        funs.add((y) -> CompletableFuture.anyOf(y, incomplete));
+        funs.add((y) -> CompletableFuture.anyOf(incomplete, y));
 
         for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
                  fun : funs) {
             CompletableFuture<Integer> f = new CompletableFuture<>();
             f.completeExceptionally(ex);
-            CompletableFuture<Integer> src = m.thenApply(f, new IncFunction(m));
+            CompletableFuture<Integer> src = m.thenApply(f, incFunction);
             checkCompletedWithWrappedException(src, ex);
             CompletableFuture<?> dep = fun.apply(src);
             checkCompletedWithWrappedException(dep, ex);
@@ -3711,7 +3926,7 @@
         for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
                  fun : funs) {
             CompletableFuture<Integer> f = new CompletableFuture<>();
-            CompletableFuture<Integer> src = m.thenApply(f, new IncFunction(m));
+            CompletableFuture<Integer> src = m.thenApply(f, incFunction);
             CompletableFuture<?> dep = fun.apply(src);
             f.completeExceptionally(ex);
             checkCompletedWithWrappedException(src, ex);
@@ -3725,7 +3940,7 @@
             CompletableFuture<Integer> f = new CompletableFuture<>();
             f.cancel(mayInterruptIfRunning);
             checkCancelled(f);
-            CompletableFuture<Integer> src = m.thenApply(f, new IncFunction(m));
+            CompletableFuture<Integer> src = m.thenApply(f, incFunction);
             checkCompletedWithWrappedCancellationException(src);
             CompletableFuture<?> dep = fun.apply(src);
             checkCompletedWithWrappedCancellationException(dep);
@@ -3736,7 +3951,7 @@
         for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
                  fun : funs) {
             CompletableFuture<Integer> f = new CompletableFuture<>();
-            CompletableFuture<Integer> src = m.thenApply(f, new IncFunction(m));
+            CompletableFuture<Integer> src = m.thenApply(f, incFunction);
             CompletableFuture<?> dep = fun.apply(src);
             f.cancel(mayInterruptIfRunning);
             checkCancelled(f);
@@ -3747,7 +3962,7 @@
     }}
 
     /**
-     * Minimal completion stages throw UOE for all non-CompletionStage methods
+     * Minimal completion stages throw UOE for most non-CompletionStage methods
      */
     public void testMinimalCompletionStage_minimality() {
         if (!testImplementationDetails) return;
@@ -3776,8 +3991,10 @@
             .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method)))
             .collect(Collectors.toList());
 
-        CompletionStage<Integer> minimalStage =
-            new CompletableFuture<Integer>().minimalCompletionStage();
+        List<CompletionStage<Integer>> stages = new ArrayList<>();
+        stages.add(new CompletableFuture<Integer>().minimalCompletionStage());
+        stages.add(CompletableFuture.completedStage(1));
+        stages.add(CompletableFuture.failedStage(new CFException()));
 
         List<Method> bugs = new ArrayList<>();
         for (Method method : allMethods) {
@@ -3793,20 +4010,22 @@
                 else if (parameterTypes[i] == long.class)
                     args[i] = 0L;
             }
-            try {
-                method.invoke(minimalStage, args);
-                bugs.add(method);
+            for (CompletionStage<Integer> stage : stages) {
+                try {
+                    method.invoke(stage, args);
+                    bugs.add(method);
+                }
+                catch (java.lang.reflect.InvocationTargetException expected) {
+                    if (! (expected.getCause() instanceof UnsupportedOperationException)) {
+                        bugs.add(method);
+                        // expected.getCause().printStackTrace();
+                    }
+                }
+                catch (ReflectiveOperationException bad) { throw new Error(bad); }
             }
-            catch (java.lang.reflect.InvocationTargetException expected) {
-                if (! (expected.getCause() instanceof UnsupportedOperationException)) {
-                    bugs.add(method);
-                    // expected.getCause().printStackTrace();
-                }
-            }
-            catch (ReflectiveOperationException bad) { throw new Error(bad); }
         }
         if (!bugs.isEmpty())
-            throw new Error("Methods did not throw UOE: " + bugs.toString());
+            throw new Error("Methods did not throw UOE: " + bugs);
     }
 
     static class Monad {
@@ -3955,12 +4174,33 @@
                                  Monad.plus(godot, Monad.unit(5L)));
     }
 
+    /** Test long recursive chains of CompletableFutures with cascading completions */
+    public void testRecursiveChains() throws Throwable {
+        for (ExecutionMode m : ExecutionMode.values())
+        for (boolean addDeadEnds : new boolean[] { true, false })
+    {
+        final int val = 42;
+        final int n = expensiveTests ? 1_000 : 2;
+        CompletableFuture<Integer> head = new CompletableFuture<>();
+        CompletableFuture<Integer> tail = head;
+        for (int i = 0; i < n; i++) {
+            if (addDeadEnds) m.thenApply(tail, v -> v + 1);
+            tail = m.thenApply(tail, v -> v + 1);
+            if (addDeadEnds) m.applyToEither(tail, tail, v -> v + 1);
+            tail = m.applyToEither(tail, tail, v -> v + 1);
+            if (addDeadEnds) m.thenCombine(tail, tail, (v, w) -> v + 1);
+            tail = m.thenCombine(tail, tail, (v, w) -> v + 1);
+        }
+        head.complete(val);
+        assertEquals(val + 3 * n, (int) tail.join());
+    }}
+
     /**
      * A single CompletableFuture with many dependents.
      * A demo of scalability - runtime is O(n).
      */
     public void testManyDependents() throws Throwable {
-        final int n = 1_000;
+        final int n = expensiveTests ? 1_000_000 : 10;
         final CompletableFuture<Void> head = new CompletableFuture<>();
         final CompletableFuture<Void> complete = CompletableFuture.completedFuture((Void)null);
         final AtomicInteger count = new AtomicInteger(0);
@@ -3987,6 +4227,97 @@
         assertEquals(5 * 3 * n, count.get());
     }
 
+    /** ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest tck */
+    public void testCoCompletionGarbageRetention() throws Throwable {
+        final int n = expensiveTests ? 1_000_000 : 10;
+        final CompletableFuture<Integer> incomplete = new CompletableFuture<>();
+        CompletableFuture<Integer> f;
+        for (int i = 0; i < n; i++) {
+            f = new CompletableFuture<>();
+            f.runAfterEither(incomplete, () -> {});
+            f.complete(null);
+
+            f = new CompletableFuture<>();
+            f.acceptEither(incomplete, (x) -> {});
+            f.complete(null);
+
+            f = new CompletableFuture<>();
+            f.applyToEither(incomplete, (x) -> x);
+            f.complete(null);
+
+            f = new CompletableFuture<>();
+            CompletableFuture.anyOf(new CompletableFuture<?>[] { f, incomplete });
+            f.complete(null);
+        }
+
+        for (int i = 0; i < n; i++) {
+            f = new CompletableFuture<>();
+            incomplete.runAfterEither(f, () -> {});
+            f.complete(null);
+
+            f = new CompletableFuture<>();
+            incomplete.acceptEither(f, (x) -> {});
+            f.complete(null);
+
+            f = new CompletableFuture<>();
+            incomplete.applyToEither(f, (x) -> x);
+            f.complete(null);
+
+            f = new CompletableFuture<>();
+            CompletableFuture.anyOf(new CompletableFuture<?>[] { incomplete, f });
+            f.complete(null);
+        }
+    }
+
+    /**
+     * Reproduction recipe for:
+     * 8160402: Garbage retention with CompletableFuture.anyOf
+     * cvs update -D '2016-05-01' ./src/main/java/util/concurrent/CompletableFuture.java && ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testAnyOfGarbageRetention tck; cvs update -A
+     */
+    public void testAnyOfGarbageRetention() throws Throwable {
+        for (Integer v : new Integer[] { 1, null })
+    {
+        final int n = expensiveTests ? 100_000 : 10;
+        CompletableFuture<Integer>[] fs
+            = (CompletableFuture<Integer>[]) new CompletableFuture<?>[100];
+        for (int i = 0; i < fs.length; i++)
+            fs[i] = new CompletableFuture<>();
+        fs[fs.length - 1].complete(v);
+        for (int i = 0; i < n; i++)
+            checkCompletedNormally(CompletableFuture.anyOf(fs), v);
+    }}
+
+    /**
+     * Checks for garbage retention with allOf.
+     *
+     * As of 2016-07, fails with OOME:
+     * ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testCancelledAllOfGarbageRetention tck
+     */
+    public void testCancelledAllOfGarbageRetention() throws Throwable {
+        final int n = expensiveTests ? 100_000 : 10;
+        CompletableFuture<Integer>[] fs
+            = (CompletableFuture<Integer>[]) new CompletableFuture<?>[100];
+        for (int i = 0; i < fs.length; i++)
+            fs[i] = new CompletableFuture<>();
+        for (int i = 0; i < n; i++)
+            assertTrue(CompletableFuture.allOf(fs).cancel(false));
+    }
+
+    /**
+     * Checks for garbage retention when a dependent future is
+     * cancelled and garbage-collected.
+     * 8161600: Garbage retention when source CompletableFutures are never completed
+     *
+     * As of 2016-07, fails with OOME:
+     * ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testCancelledGarbageRetention tck
+     */
+    public void testCancelledGarbageRetention() throws Throwable {
+        final int n = expensiveTests ? 100_000 : 10;
+        CompletableFuture<Integer> neverCompleted = new CompletableFuture<>();
+        for (int i = 0; i < n; i++)
+            assertTrue(neverCompleted.thenRun(() -> {}).cancel(true));
+    }
+
 //     static <U> U join(CompletionStage<U> stage) {
 //         CompletableFuture<U> f = new CompletableFuture<>();
 //         stage.whenComplete((v, ex) -> {
--- a/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -43,6 +43,8 @@
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -830,4 +832,47 @@
         }
     }
 
+    /**
+     * Tests performance of removeAll when the other collection is much smaller.
+     * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testRemoveAll_performance -Djsr166.expensiveTests=true tck
+     */
+    public void testRemoveAll_performance() {
+        final int mapSize = expensiveTests ? 1_000_000 : 100;
+        final int iterations = expensiveTests ? 500 : 2;
+        final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
+        for (int i = 0; i < mapSize; i++)
+            map.put(i, i);
+        Set<Integer> keySet = map.keySet();
+        Collection<Integer> removeMe = Arrays.asList(new Integer[] { -99, -86 });
+        for (int i = 0; i < iterations; i++)
+            assertFalse(keySet.removeAll(removeMe));
+        assertEquals(mapSize, map.size());
+    }
+
+    /**
+     * Tests performance of computeIfAbsent when the element is present.
+     * See JDK-8161372
+     * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testcomputeIfAbsent_performance -Djsr166.expensiveTests=true tck
+     */
+    public void testcomputeIfAbsent_performance() {
+        final int mapSize = 20;
+        final int iterations = expensiveTests ? (1 << 23) : mapSize * 2;
+        final int threads = expensiveTests ? 10 : 2;
+        final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
+        for (int i = 0; i < mapSize; i++)
+            map.put(i, i);
+        final ExecutorService pool = Executors.newFixedThreadPool(2);
+        try (PoolCleaner cleaner = cleaner(pool)) {
+            Runnable r = new CheckedRunnable() {
+                public void realRun() {
+                    int result = 0;
+                    for (int i = 0; i < iterations; i++)
+                        result += map.computeIfAbsent(i % mapSize, (k) -> k + k);
+                    if (result == -42) throw new Error();
+                }};
+            for (int i = 0; i < threads; i++)
+                pool.execute(r);
+        }
+    }
+
 }
--- a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java	Wed Jul 05 22:00:06 2017 +0200
@@ -548,6 +548,13 @@
         // Java9+ test classes
         if (atLeastJava9()) {
             String[] java9TestClassNames = {
+                "AtomicBoolean9Test",
+                "AtomicInteger9Test",
+                "AtomicIntegerArray9Test",
+                "AtomicLong9Test",
+                "AtomicLongArray9Test",
+                "AtomicReference9Test",
+                "AtomicReferenceArray9Test",
                 "ExecutorCompletionService9Test",
             };
             addNamedTestClasses(suite, java9TestClassNames);
@@ -975,7 +982,11 @@
         }
     }
 
-    /** Like Runnable, but with the freedom to throw anything */
+    /**
+     * Like Runnable, but with the freedom to throw anything.
+     * junit folks had the same idea:
+     * http://junit.org/junit5/docs/snapshot/api/org/junit/gen5/api/Executable.html
+     */
     interface Action { public void run() throws Throwable; }
 
     /**
@@ -1006,6 +1017,15 @@
      * Uninteresting threads are filtered out.
      */
     static void dumpTestThreads() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            try {
+                System.setSecurityManager(null);
+            } catch (SecurityException giveUp) {
+                return;
+            }
+        }
+
         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
         System.err.println("------ stacktrace dump start ------");
         for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
@@ -1023,6 +1043,8 @@
             System.err.print(info);
         }
         System.err.println("------ stacktrace dump end ------");
+
+        if (sm != null) System.setSecurityManager(sm);
     }
 
     /**
--- a/jdk/test/java/util/concurrent/tck/StampedLockTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/concurrent/tck/StampedLockTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -32,11 +32,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+import static java.util.concurrent.TimeUnit.DAYS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.StampedLock;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -745,28 +752,41 @@
     public void testTryConvertToOptimisticRead() throws InterruptedException {
         StampedLock lock = new StampedLock();
         long s, p;
-        s = 0L;
-        assertFalse((p = lock.tryConvertToOptimisticRead(s)) != 0L);
+        assertEquals(0L, lock.tryConvertToOptimisticRead(0L));
+
         assertTrue((s = lock.tryOptimisticRead()) != 0L);
-        assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
+        assertEquals(s, lock.tryConvertToOptimisticRead(s));
+        assertTrue(lock.validate(s));
+
+        assertTrue((p = lock.readLock()) != 0L);
+        assertTrue((s = lock.tryOptimisticRead()) != 0L);
+        assertEquals(s, lock.tryConvertToOptimisticRead(s));
+        assertTrue(lock.validate(s));
+        lock.unlockRead(p);
+
         assertTrue((s = lock.writeLock()) != 0L);
         assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
         assertTrue(lock.validate(p));
+
         assertTrue((s = lock.readLock()) != 0L);
         assertTrue(lock.validate(s));
         assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
         assertTrue(lock.validate(p));
+
         assertTrue((s = lock.tryWriteLock()) != 0L);
         assertTrue(lock.validate(s));
         assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
         assertTrue(lock.validate(p));
+
         assertTrue((s = lock.tryReadLock()) != 0L);
         assertTrue(lock.validate(s));
         assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
         assertTrue(lock.validate(p));
+
         assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
         assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
         assertTrue(lock.validate(p));
+
         assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
         assertTrue(lock.validate(s));
         assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L);
@@ -780,39 +800,67 @@
     public void testTryConvertToReadLock() throws InterruptedException {
         StampedLock lock = new StampedLock();
         long s, p;
-        s = 0L;
-        assertFalse((p = lock.tryConvertToReadLock(s)) != 0L);
+
+        assertFalse((p = lock.tryConvertToReadLock(0L)) != 0L);
+
         assertTrue((s = lock.tryOptimisticRead()) != 0L);
         assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
+        assertTrue(lock.isReadLocked());
+        assertEquals(1, lock.getReadLockCount());
         lock.unlockRead(p);
+
+        assertTrue((s = lock.tryOptimisticRead()) != 0L);
+        lock.readLock();
+        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
+        assertTrue(lock.isReadLocked());
+        assertEquals(2, lock.getReadLockCount());
+        lock.unlockRead(p);
+        lock.unlockRead(p);
+
         assertTrue((s = lock.writeLock()) != 0L);
         assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
         assertTrue(lock.validate(p));
+        assertTrue(lock.isReadLocked());
+        assertEquals(1, lock.getReadLockCount());
         lock.unlockRead(p);
+
         assertTrue((s = lock.readLock()) != 0L);
         assertTrue(lock.validate(s));
-        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
-        assertTrue(lock.validate(p));
-        lock.unlockRead(p);
+        assertEquals(s, lock.tryConvertToReadLock(s));
+        assertTrue(lock.validate(s));
+        assertTrue(lock.isReadLocked());
+        assertEquals(1, lock.getReadLockCount());
+        lock.unlockRead(s);
+
         assertTrue((s = lock.tryWriteLock()) != 0L);
         assertTrue(lock.validate(s));
         assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
         assertTrue(lock.validate(p));
+        assertEquals(1, lock.getReadLockCount());
         lock.unlockRead(p);
+
         assertTrue((s = lock.tryReadLock()) != 0L);
         assertTrue(lock.validate(s));
-        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
-        assertTrue(lock.validate(p));
-        lock.unlockRead(p);
+        assertEquals(s, lock.tryConvertToReadLock(s));
+        assertTrue(lock.validate(s));
+        assertTrue(lock.isReadLocked());
+        assertEquals(1, lock.getReadLockCount());
+        lock.unlockRead(s);
+
         assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
         assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
         assertTrue(lock.validate(p));
+        assertTrue(lock.isReadLocked());
+        assertEquals(1, lock.getReadLockCount());
         lock.unlockRead(p);
+
         assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
         assertTrue(lock.validate(s));
-        assertTrue((p = lock.tryConvertToReadLock(s)) != 0L);
-        assertTrue(lock.validate(p));
-        lock.unlockRead(p);
+        assertEquals(s, lock.tryConvertToReadLock(s));
+        assertTrue(lock.validate(s));
+        assertTrue(lock.isReadLocked());
+        assertEquals(1, lock.getReadLockCount());
+        lock.unlockRead(s);
     }
 
     /**
@@ -822,38 +870,52 @@
     public void testTryConvertToWriteLock() throws InterruptedException {
         StampedLock lock = new StampedLock();
         long s, p;
-        s = 0L;
-        assertFalse((p = lock.tryConvertToWriteLock(s)) != 0L);
+
+        assertFalse((p = lock.tryConvertToWriteLock(0L)) != 0L);
+
         assertTrue((s = lock.tryOptimisticRead()) != 0L);
         assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
+        assertTrue(lock.isWriteLocked());
         lock.unlockWrite(p);
+
         assertTrue((s = lock.writeLock()) != 0L);
-        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
-        assertTrue(lock.validate(p));
-        lock.unlockWrite(p);
+        assertEquals(s, lock.tryConvertToWriteLock(s));
+        assertTrue(lock.validate(s));
+        assertTrue(lock.isWriteLocked());
+        lock.unlockWrite(s);
+
         assertTrue((s = lock.readLock()) != 0L);
         assertTrue(lock.validate(s));
         assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
         assertTrue(lock.validate(p));
+        assertTrue(lock.isWriteLocked());
         lock.unlockWrite(p);
+
         assertTrue((s = lock.tryWriteLock()) != 0L);
         assertTrue(lock.validate(s));
-        assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
-        assertTrue(lock.validate(p));
-        lock.unlockWrite(p);
+        assertEquals(s, lock.tryConvertToWriteLock(s));
+        assertTrue(lock.validate(s));
+        assertTrue(lock.isWriteLocked());
+        lock.unlockWrite(s);
+
         assertTrue((s = lock.tryReadLock()) != 0L);
         assertTrue(lock.validate(s));
         assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
         assertTrue(lock.validate(p));
+        assertTrue(lock.isWriteLocked());
         lock.unlockWrite(p);
+
         assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L);
         assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
         assertTrue(lock.validate(p));
+        assertTrue(lock.isWriteLocked());
         lock.unlockWrite(p);
+
         assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L);
         assertTrue(lock.validate(s));
         assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L);
         assertTrue(lock.validate(p));
+        assertTrue(lock.isWriteLocked());
         lock.unlockWrite(p);
     }
 
@@ -903,4 +965,241 @@
         assertTrue(lock.tryLock());
     }
 
+    /**
+     * Lock.newCondition throws UnsupportedOperationException
+     */
+    public void testLockViewsDoNotSupportConditions() {
+        StampedLock sl = new StampedLock();
+        assertThrows(UnsupportedOperationException.class,
+                     () -> sl.asWriteLock().newCondition(),
+                     () -> sl.asReadLock().newCondition(),
+                     () -> sl.asReadWriteLock().writeLock().newCondition(),
+                     () -> sl.asReadWriteLock().readLock().newCondition());
+    }
+
+    /**
+     * Passing optimistic read stamps to unlock operations result in
+     * IllegalMonitorStateException
+     */
+    public void testCannotUnlockOptimisticReadStamps() {
+        Runnable[] actions = {
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryOptimisticRead();
+                assertTrue(stamp != 0);
+                sl.unlockRead(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryOptimisticRead();
+                sl.unlock(stamp);
+            },
+
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryOptimisticRead();
+                sl.writeLock();
+                sl.unlock(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryOptimisticRead();
+                sl.readLock();
+                sl.unlockRead(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryOptimisticRead();
+                sl.readLock();
+                sl.unlock(stamp);
+            },
+
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
+                assertTrue(stamp != 0);
+                sl.writeLock();
+                sl.unlockWrite(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
+                sl.writeLock();
+                sl.unlock(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
+                sl.readLock();
+                sl.unlockRead(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.writeLock());
+                sl.readLock();
+                sl.unlock(stamp);
+            },
+
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
+                assertTrue(stamp != 0);
+                sl.writeLock();
+                sl.unlockWrite(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
+                sl.writeLock();
+                sl.unlock(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
+                sl.readLock();
+                sl.unlockRead(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                sl.readLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
+                assertTrue(stamp != 0);
+                sl.readLock();
+                sl.unlockRead(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
+                sl.readLock();
+                sl.unlock(stamp);
+            },
+            () -> {
+                StampedLock sl = new StampedLock();
+                sl.readLock();
+                long stamp = sl.tryConvertToOptimisticRead(sl.readLock());
+                sl.readLock();
+                sl.unlock(stamp);
+            },
+        };
+
+        assertThrows(IllegalMonitorStateException.class, actions);
+    }
+
+    static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
+        try { return sl.writeLockInterruptibly(); }
+        catch (InterruptedException ex) { throw new AssertionError(ex); }
+    }
+
+    static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
+        try { return sl.tryWriteLock(time, unit); }
+        catch (InterruptedException ex) { throw new AssertionError(ex); }
+    }
+
+    static long readLockInterruptiblyUninterrupted(StampedLock sl) {
+        try { return sl.readLockInterruptibly(); }
+        catch (InterruptedException ex) { throw new AssertionError(ex); }
+    }
+
+    static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
+        try { return sl.tryReadLock(time, unit); }
+        catch (InterruptedException ex) { throw new AssertionError(ex); }
+    }
+
+    /**
+     * Invalid write stamps result in IllegalMonitorStateException
+     */
+    public void testInvalidWriteStampsThrowIllegalMonitorStateException() {
+        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
+        writeLockers.add((sl) -> sl.writeLock());
+        writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
+        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
+
+        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
+        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
+        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
+        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
+        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+
+        List<Consumer<StampedLock>> mutaters = new ArrayList<>();
+        mutaters.add((sl) -> {});
+        mutaters.add((sl) -> sl.readLock());
+        for (Function<StampedLock, Long> writeLocker : writeLockers)
+            mutaters.add((sl) -> writeLocker.apply(sl));
+
+        for (Function<StampedLock, Long> writeLocker : writeLockers)
+        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers)
+        for (Consumer<StampedLock> mutater : mutaters) {
+            final StampedLock sl = new StampedLock();
+            final long stamp = writeLocker.apply(sl);
+            assertTrue(stamp != 0L);
+            assertThrows(IllegalMonitorStateException.class,
+                         () -> sl.unlockRead(stamp));
+            writeUnlocker.accept(sl, stamp);
+            mutater.accept(sl);
+            assertThrows(IllegalMonitorStateException.class,
+                         () -> sl.unlock(stamp),
+                         () -> sl.unlockRead(stamp),
+                         () -> sl.unlockWrite(stamp));
+        }
+    }
+
+    /**
+     * Invalid read stamps result in IllegalMonitorStateException
+     */
+    public void testInvalidReadStampsThrowIllegalMonitorStateException() {
+        List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
+        readLockers.add((sl) -> sl.readLock());
+        readLockers.add((sl) -> readLockInterruptiblyUninterrupted(sl));
+        readLockers.add((sl) -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+        readLockers.add((sl) -> tryReadLockUninterrupted(sl, 0, DAYS));
+
+        List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
+        readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
+        readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
+        readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
+        readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+
+        List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
+        writeLockers.add((sl) -> sl.writeLock());
+        writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
+        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
+
+        List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
+        writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
+        writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
+        writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
+        writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+
+
+        for (Function<StampedLock, Long> readLocker : readLockers)
+        for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers)
+        for (Function<StampedLock, Long> writeLocker : writeLockers)
+        for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers) {
+            final StampedLock sl = new StampedLock();
+            final long stamp = readLocker.apply(sl);
+            assertTrue(stamp != 0L);
+            assertThrows(IllegalMonitorStateException.class,
+                         () -> sl.unlockWrite(stamp));
+            readUnlocker.accept(sl, stamp);
+            assertThrows(IllegalMonitorStateException.class,
+                         () -> sl.unlock(stamp),
+                         () -> sl.unlockRead(stamp),
+                         () -> sl.unlockWrite(stamp));
+            final long writeStamp = writeLocker.apply(sl);
+            assertTrue(writeStamp != 0L);
+            assertTrue(writeStamp != stamp);
+            assertThrows(IllegalMonitorStateException.class,
+                         () -> sl.unlock(stamp),
+                         () -> sl.unlockRead(stamp),
+                         () -> sl.unlockWrite(stamp));
+            writeUnlocker.accept(sl, writeStamp);
+            assertThrows(IllegalMonitorStateException.class,
+                         () -> sl.unlock(stamp),
+                         () -> sl.unlockRead(stamp),
+                         () -> sl.unlockWrite(stamp));
+        }
+    }
+
 }
--- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarIterators.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8132734 8144062
- * @summary Test the extended API and the aliasing additions in JarFile that
- *          support multi-release jar files
- * @library /lib/testlibrary/java/util/jar
- * @build Compiler JarBuilder CreateMultiReleaseTestJars
- * @run testng MultiReleaseJarIterators
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Collectors;
-import java.util.zip.ZipFile;
-
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-
-public class MultiReleaseJarIterators {
-
-    static final int MAJOR_VERSION = Runtime.version().major();
-
-    String userdir = System.getProperty("user.dir", ".");
-    File unversioned = new File(userdir, "unversioned.jar");
-    File multirelease = new File(userdir, "multi-release.jar");
-    Map<String,JarEntry> uvEntries = new HashMap<>();
-    Map<String,JarEntry> mrEntries = new HashMap<>();
-    Map<String,JarEntry> baseEntries = new HashMap<>();
-    Map<String,JarEntry> v9Entries = new HashMap<>();
-    Map<String, JarEntry> v10Entries = new HashMap<>();
-
-    @BeforeClass
-    public void initialize() throws Exception {
-        CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
-        creator.compileEntries();
-        creator.buildUnversionedJar();
-        creator.buildMultiReleaseJar();
-
-        try (JarFile jf = new JarFile(multirelease)) {
-            for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements(); ) {
-                JarEntry je = e.nextElement();
-                String name = je.getName();
-                mrEntries.put(name, je);
-                if (name.startsWith("META-INF/versions/")) {
-                    if (name.startsWith("META-INF/versions/9/")) {
-                        v9Entries.put(name.substring(20), je);
-                    } else if (name.startsWith("META-INF/versions/10/")) {
-                        v10Entries.put(name.substring(21), je);
-                    }
-                } else {
-                    baseEntries.put(name, je);
-                }
-            }
-        }
-        Assert.assertEquals(mrEntries.size(), 14);
-        Assert.assertEquals(baseEntries.size(), 6);
-        Assert.assertEquals(v9Entries.size(), 5);
-        Assert.assertEquals(v10Entries.size(), 3);
-
-        try (JarFile jf = new JarFile(unversioned)) {
-            jf.entries().asIterator().forEachRemaining(je -> uvEntries.put(je.getName(), je));
-        }
-        Assert.assertEquals(uvEntries.size(), 6);
-    }
-
-    @AfterClass
-    public void close() throws IOException {
-        Files.delete(unversioned.toPath());
-        Files.delete(multirelease.toPath());
-    }
-
-    @Test
-    public void testMultiReleaseJar() throws IOException {
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ)) {
-            testEnumeration(jf, mrEntries);
-            testStream(jf, mrEntries);
-        }
-
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, JarFile.baseVersion())) {
-            testEnumeration(jf, baseEntries);
-            testStream(jf, baseEntries);
-        }
-
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.Version.parse("9"))) {
-            testEnumeration(jf, v9Entries);
-            testStream(jf, v9Entries);
-        }
-
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.version())) {
-            Map<String,JarEntry> expectedEntries;
-            switch (MAJOR_VERSION) {
-                case 9:
-                    expectedEntries = v9Entries;
-                    break;
-                case 10:  // won't get here until JDK 10
-                    expectedEntries = v10Entries;
-                    break;
-                default:
-                    expectedEntries = baseEntries;
-                    break;
-            }
-
-            testEnumeration(jf, expectedEntries);
-            testStream(jf, expectedEntries);
-        }
-    }
-
-    @Test
-    public void testUnversionedJar() throws IOException {
-        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ)) {
-            testEnumeration(jf, uvEntries);
-            testStream(jf, uvEntries);
-        }
-
-        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, JarFile.baseVersion())) {
-            testEnumeration(jf, uvEntries);
-            testStream(jf, uvEntries);
-        }
-
-        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Runtime.Version.parse("9"))) {
-            testEnumeration(jf, uvEntries);
-            testStream(jf, uvEntries);
-        }
-
-        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Runtime.version())) {
-            testEnumeration(jf, uvEntries);
-            testStream(jf, uvEntries);
-        }
-    }
-
-    private void testEnumeration(JarFile jf, Map<String,JarEntry> expectedEntries) {
-        Map<String, JarEntry> actualEntries = new HashMap<>();
-        for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements(); ) {
-            JarEntry je = e.nextElement();
-            actualEntries.put(je.getName(), je);
-        }
-
-        testEntries(jf, actualEntries, expectedEntries);
-    }
-
-
-    private void testStream(JarFile jf, Map<String,JarEntry> expectedEntries) {
-        Map<String,JarEntry> actualEntries = jf.stream().collect(Collectors.toMap(je -> je.getName(), je -> je));
-
-        testEntries(jf, actualEntries, expectedEntries);
-    }
-
-    private void testEntries(JarFile jf, Map<String,JarEntry> actualEntries, Map<String,JarEntry> expectedEntries) {
-        /* For multi-release jar files constructed with a Release object,
-         * actualEntries contain versionedEntries that are considered part of the
-         * public API.  They have a 1-1 correspondence with baseEntries,
-         * so entries that are not part of the public API won't be present,
-         * i.e. those entries with a name that starts with version/PackagePrivate
-         * in this particular jar file (multi-release.jar)
-         */
-
-        Map<String,JarEntry> entries;
-        if (expectedEntries == mrEntries) {
-            Assert.assertEquals(actualEntries.size(), mrEntries.size());
-            entries = mrEntries;
-        } else if (expectedEntries == uvEntries) {
-            Assert.assertEquals(actualEntries.size(), uvEntries.size());
-            entries = uvEntries;
-        } else {
-            Assert.assertEquals(actualEntries.size(), baseEntries.size());  // this is correct
-            entries = baseEntries;
-        }
-
-        entries.keySet().forEach(name -> {
-            JarEntry ee = expectedEntries.get(name);
-            if (ee == null) ee = entries.get(name);
-            JarEntry ae = actualEntries.get(name);
-            try {
-                compare(jf, ae, ee);
-            } catch (IOException x) {
-                throw new RuntimeException(x);
-            }
-        });
-    }
-
-    private void compare(JarFile jf, JarEntry actual, JarEntry expected) throws IOException {
-        byte[] abytes;
-        byte[] ebytes;
-
-        try (InputStream is = jf.getInputStream(actual)) {
-            abytes = is.readAllBytes();
-        }
-
-        try (InputStream is = jf.getInputStream(expected)) {
-            ebytes = is.readAllBytes();
-        }
-
-        Assert.assertEquals(abytes, ebytes);
-    }
-}
--- a/jdk/test/java/util/zip/TestExtraTime.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/zip/TestExtraTime.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 4759491 6303183 7012868 8015666 8023713 8068790 8076641 8075526 8130914
+ * @bug 4759491 6303183 7012868 8015666 8023713 8068790 8076641 8075526 8130914 8161942
  * @summary Test ZOS and ZIS timestamp in extra field correctly
  */
 
@@ -32,6 +32,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.attribute.FileTime;
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
@@ -40,37 +41,52 @@
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 
+
+
 public class TestExtraTime {
 
     public static void main(String[] args) throws Throwable{
 
         File src = new File(System.getProperty("test.src", "."), "TestExtraTime.java");
-        if (src.exists()) {
+        if (!src.exists()) {
+            return;
+        }
+
+        TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
+
+        for (byte[] extra : new byte[][] { null, new byte[] {1, 2, 3}}) {
+
+            // ms-dos 1980 epoch problem
+            test0(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null, extra);
+            // negative epoch time
+            test0(FileTime.from(-100, TimeUnit.DAYS), null, null, null, extra);
+
             long time = src.lastModified();
-            FileTime mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
-            FileTime atime = FileTime.from(time + 300000, TimeUnit.MILLISECONDS);
-            FileTime ctime = FileTime.from(time - 300000, TimeUnit.MILLISECONDS);
-            TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
-
-            for (byte[] extra : new byte[][] { null, new byte[] {1, 2, 3}}) {
-                test(mtime, null, null, null, extra);
+            test(FileTime.from(time, TimeUnit.MILLISECONDS),
+                 FileTime.from(time + 300000, TimeUnit.MILLISECONDS),
+                 FileTime.from(time - 300000, TimeUnit.MILLISECONDS),
+                 tz, extra);
 
-                // ms-dos 1980 epoch problem
-                test(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null, extra);
-                // negative epoch time
-                test(FileTime.from(-100, TimeUnit.DAYS), null, null, null, extra);
-
-                // non-default tz
-                test(mtime, null, null, tz, extra);
+            // now
+            time = Instant.now().toEpochMilli();
+            test(FileTime.from(time, TimeUnit.MILLISECONDS),
+                 FileTime.from(time + 300000, TimeUnit.MILLISECONDS),
+                 FileTime.from(time - 300000, TimeUnit.MILLISECONDS),
+                 tz, extra);
 
-                test(mtime, atime, null, null, extra);
-                test(mtime, null, ctime, null, extra);
-                test(mtime, atime, ctime, null, extra);
+            // unix 2038
+            time = 0x80000000L;
+            test(FileTime.from(time, TimeUnit.SECONDS),
+                 FileTime.from(time, TimeUnit.SECONDS),
+                 FileTime.from(time, TimeUnit.SECONDS),
+                 tz, extra);
 
-                test(mtime, atime, null, tz, extra);
-                test(mtime, null, ctime, tz, extra);
-                test(mtime, atime, ctime, tz, extra);
-            }
+            // mtime < unix 2038
+            time = 0x7fffffffL;
+            test(FileTime.from(time, TimeUnit.SECONDS),
+                 FileTime.from(time + 30000, TimeUnit.SECONDS),
+                 FileTime.from(time + 30000, TimeUnit.SECONDS),
+                 tz, extra);
         }
 
         testNullHandling();
@@ -80,6 +96,18 @@
 
     static void test(FileTime mtime, FileTime atime, FileTime ctime,
                      TimeZone tz, byte[] extra) throws Throwable {
+        test0(mtime, null, null, null, extra);
+        test0(mtime, null, null, tz, extra);    // non-default tz
+        test0(mtime, atime, null, null, extra);
+        test0(mtime, null, ctime, null, extra);
+        test0(mtime, atime, ctime, null, extra);
+        test0(mtime, atime, null, tz, extra);
+        test0(mtime, null, ctime, tz, extra);
+        test0(mtime, atime, ctime, tz, extra);
+    }
+
+    static void test0(FileTime mtime, FileTime atime, FileTime ctime,
+                     TimeZone tz, byte[] extra) throws Throwable {
         System.out.printf("--------------------%nTesting: [%s]/[%s]/[%s]%n",
                           mtime, atime, ctime);
         TimeZone tz0 = TimeZone.getDefault();
@@ -120,13 +148,14 @@
         Path zpath = Paths.get(System.getProperty("test.dir", "."),
                                "TestExtraTime.zip");
         Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath);
-        ZipFile zf = new ZipFile(zpath.toFile());
-        ze = zf.getEntry("TestExtraTime.java");
-        // ZipFile read entry from cen, which does not have a/ctime,
-        // for now.
-        check(mtime, null, null, ze, extra);
-        zf.close();
-        Files.delete(zpath);
+        try (ZipFile zf = new ZipFile(zpath.toFile())) {
+            ze = zf.getEntry("TestExtraTime.java");
+            // ZipFile read entry from cen, which does not have a/ctime,
+            // for now.
+            check(mtime, null, null, ze, extra);
+        } finally {
+            Files.delete(zpath);
+        }
     }
 
     static void check(FileTime mtime, FileTime atime, FileTime ctime,
--- a/jdk/test/java/util/zip/TestLocalTime.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/java/util/zip/TestLocalTime.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8075526 8135108
+ * @bug 8075526 8135108 8155616 8161942
  * @summary Test timestamp via ZipEntry.get/setTimeLocal()
  */
 
@@ -39,14 +39,13 @@
     public static void main(String[] args) throws Throwable{
         try {
             LocalDateTime ldt = LocalDateTime.now();
-            test(getBytes(ldt), ldt);    // now
-
-            ldt = ldt.withYear(1968); test(getBytes(ldt), ldt);
-            ldt = ldt.withYear(1970); test(getBytes(ldt), ldt);
-            ldt = ldt.withYear(1982); test(getBytes(ldt), ldt);
-            ldt = ldt.withYear(2037); test(getBytes(ldt), ldt);
-            ldt = ldt.withYear(2100); test(getBytes(ldt), ldt);
-            ldt = ldt.withYear(2106); test(getBytes(ldt), ldt);
+            test(ldt);    // now
+            test(ldt.withYear(1968));
+            test(ldt.withYear(1970));
+            test(ldt.withYear(1982));
+            test(ldt.withYear(2037));
+            test(ldt.withYear(2100));
+            test(ldt.withYear(2106));
 
             TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
             // dos time does not support < 1980, have to use
@@ -57,10 +56,17 @@
             testWithTZ(tz, ldt.withYear(2106));
 
             // for #8135108
-            ldt = LocalDateTime.of(2100, 12, 06, 12, 34, 34, 973);
-            test(getBytes(ldt), ldt);
-            ldt = LocalDateTime.of(2106, 12, 06, 12, 34, 34, 973);
-            test(getBytes(ldt), ldt);
+            test(LocalDateTime.of(2100, 12, 06, 12, 34, 34, 973));
+            test(LocalDateTime.of(2106, 12, 06, 12, 34, 34, 973));
+
+            // for #8155616
+            test(LocalDateTime.of(2016, 03, 13, 2, 50, 00));  // gap
+            test(LocalDateTime.of(2015, 11, 1,  1, 30, 00));  // overlap
+            test(LocalDateTime.of(1968, 04, 28, 2, 51, 25));
+            test(LocalDateTime.of(1970, 04, 26, 2, 31, 52));
+
+            // for #8161942
+            test(LocalDateTime.of(2200, 04, 26, 2, 31, 52));  // unix 2038
 
         } finally {
             TimeZone.setDefault(tz0);
@@ -73,7 +79,6 @@
         ZipEntry ze = new ZipEntry("TestLocalTime.java");
         ze.setTimeLocal(mtime);
         check(ze, mtime);
-
         zos.putNextEntry(ze);
         zos.write(new byte[] { 1, 2, 3, 4});
         zos.close();
@@ -87,6 +92,10 @@
        test(zbytes, ldt);
     }
 
+    static void test(LocalDateTime ldt) throws Throwable {
+        test(getBytes(ldt), ldt);
+    }
+
     static void test(byte[] zbytes, LocalDateTime expected) throws Throwable {
         System.out.printf("--------------------%nTesting: [%s]%n", expected);
         // ZipInputStream
@@ -113,6 +122,23 @@
         LocalDateTime ldt = ze.getTimeLocal();
         if (ldt.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1
             != expected.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1) {
+            // if the LDT is out of the range of the standard ms-dos date-time
+            // format ( < 1980 ) AND the date-time is within the daylight saving
+            // time gap (which means the LDT is actually "invalid"), the LDT will
+            // be adjusted accordingly when ZipEntry.setTimeLocal() converts the
+            // date-time via ldt -> zdt -> Instant -> FileTime.
+            // See ZonedDateTime.of(LocalDateTime, ZoneId) for more details.
+            if (ldt.getYear() < 1980 || ldt.getYear() > (1980 + 0x7f)) {
+                System.out.println(" Non-MSDOS    ldt : " + ldt);
+                System.out.println("         expected : " + expected);
+                // try to adjust the "expected", assume daylight saving gap
+                expected = ZonedDateTime.of(expected, ZoneId.systemDefault())
+                                        .toLocalDateTime();
+                if (ldt.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1
+                    == expected.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1) {
+                    return;
+                }
+            }
             throw new RuntimeException("Timestamp: storing mtime failed!");
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/templates/SSLSocketSample.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// Please run in othervm mode.  SunJSSE does not support dynamic system
+// properties, no way to re-use system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8161106
+ * @summary Improve SSLSocket test template
+ * @run main/othervm SSLSocketSample
+ */
+
+import java.io.*;
+import javax.net.ssl.*;
+import java.net.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Template to help speed your client/server tests.
+ */
+public final class SSLSocketSample {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    private static final boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+
+    /*
+     * Turn on SSL debugging?
+     */
+    private static final boolean debug = false;
+
+    /*
+     * Is the server ready to serve?
+     */
+    private static final CountDownLatch serverCondition = new CountDownLatch(1);
+
+    /*
+     * Is the client ready to handshake?
+     */
+    private static final CountDownLatch clientCondition = new CountDownLatch(1);
+
+    /*
+     * What's the server port?  Use any free port by default
+     */
+    private volatile int serverPort = 0;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocket sslServerSocket;
+
+        // kick start the server side service
+        SSLServerSocketFactory sslssf =
+                (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
+        sslServerSocket =
+                (SSLServerSocket)sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        // Signal the client, the server is ready to accept connection.
+        serverCondition.countDown();
+
+
+        // Try to accept a connection in 30 seconds.
+        SSLSocket sslSocket;
+        try {
+            sslServerSocket.setSoTimeout(30000);
+            sslSocket = (SSLSocket)sslServerSocket.accept();
+        } catch (SocketTimeoutException ste) {
+            sslServerSocket.close();
+
+            // Ignore the test case if no connection within 30 seconds.
+            System.out.println(
+                "No incoming client connection in 30 seconds. " +
+                "Ignore in server side.");
+            return;
+        }
+
+        // handle the connection
+        try {
+            // Is it the expected client connection?
+            //
+            // Naughty test cases or third party routines may try to
+            // connection to this server port unintentionally.  In
+            // order to mitigate the impact of unexpected client
+            // connections and avoid intermittent failure, it should
+            // be checked that the accepted connection is really linked
+            // to the expected client.
+            boolean clientIsReady =
+                    clientCondition.await(30L, TimeUnit.SECONDS);
+
+            if (clientIsReady) {
+                // Run the application in server side.
+                runServerApplication(sslSocket);
+            } else {    // Otherwise, ignore
+                // We don't actually care about plain socket connections
+                // for TLS communication testing generally.  Just ignore
+                // the test if the accepted connection is not linked to
+                // the expected client or the client connection timeout
+                // in 30 seconds.
+                System.out.println(
+                        "The client is not the expected one or timeout. " +
+                        "Ignore in server side.");
+            }
+        } finally {
+            sslSocket.close();
+            sslServerSocket.close();
+        }
+    }
+
+    /*
+     * Define the server side application of the test for the specified socket.
+     */
+    void runServerApplication(SSLSocket socket) throws Exception {
+        // here comes the test logic
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+    }
+
+    /*
+     * Define the client side of the test.
+     */
+    void doClientSide() throws Exception {
+
+        // Wait for server to get started.
+        //
+        // The server side takes care of the issue if the server cannot
+        // get started in 90 seconds.  The client side would just ignore
+        // the test case if the serer is not ready.
+        boolean serverIsReady =
+                serverCondition.await(90L, TimeUnit.SECONDS);
+        if (!serverIsReady) {
+            System.out.println(
+                    "The server is not ready yet in 90 seconds. " +
+                    "Ignore in client side.");
+            return;
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory)SSLSocketFactory.getDefault();
+        try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
+            try {
+                sslSocket.connect(
+                        new InetSocketAddress("localhost", serverPort), 15000);
+            } catch (IOException ioe) {
+                // The server side may be impacted by naughty test cases or
+                // third party routines, and cannot accept connections.
+                //
+                // Just ignore the test if the connection cannot be
+                // established.
+                System.out.println(
+                        "Cannot make a connection in 15 seconds. " +
+                        "Ignore in client side.");
+                return;
+            }
+
+            // OK, here the client and server get connected.
+
+            // Signal the server, the client is ready to communicate.
+            clientCondition.countDown();
+
+            // There is still a chance in theory that the server thread may
+            // wait client-ready timeout and then quit.  The chance should
+            // be really rare so we don't consider it until it becomes a
+            // real problem.
+
+            // Run the application in client side.
+            runClientApplication(sslSocket);
+        }
+    }
+
+    /*
+     * Define the server side application of the test for the specified socket.
+     */
+    void runClientApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    private volatile Exception serverException = null;
+    private volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Start the tests.
+         */
+        new SSLSocketSample();
+    }
+
+    private Thread clientThread = null;
+    private Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SSLSocketSample() throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.out.println("Server died: " + e);
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                System.out.println("Server failed: " + e);
+                serverException = e;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.out.println("Client died: " + e);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                System.out.println("Client failed: " + e);
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/security/auth/login/modules/JaasClientWithDefaultHandler.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package login;
+
+import java.security.Principal;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import com.sun.security.auth.UnixPrincipal;
+
+public class JaasClientWithDefaultHandler {
+
+    private static final String USER_NAME = "testUser";
+    private static final String LOGIN_CONTEXT = "ModularLoginConf";
+    private static final String CBH_PROP = "auth.login.defaultCallbackHandler";
+
+    public static void main(String[] args) {
+        try {
+            java.security.Security.setProperty(CBH_PROP, args[0]);
+            LoginContext lc = new LoginContext(LOGIN_CONTEXT);
+            lc.login();
+            checkPrincipal(lc, true);
+            lc.logout();
+            checkPrincipal(lc, false);
+        } catch (LoginException le) {
+            throw new RuntimeException(le);
+        }
+        System.out.println("Test passed.");
+
+    }
+
+    /*
+     * Verify principal for the test user.
+     */
+    private static void checkPrincipal(LoginContext loginContext,
+            boolean principalShouldExist) {
+        if (!principalShouldExist) {
+            if (loginContext.getSubject().getPrincipals().size() != 0) {
+                throw new RuntimeException("Test failed. Principal was not "
+                        + "cleared.");
+            }
+            return;
+        }
+        for (Principal p : loginContext.getSubject().getPrincipals()) {
+            if (p instanceof UnixPrincipal
+                    && USER_NAME.equals(p.getName())) {
+                //Proper principal was found, return.
+                return;
+            }
+        }
+        throw new RuntimeException("Test failed. UnixPrincipal "
+                + USER_NAME + " expected.");
+    }
+
+}
--- a/jdk/test/javax/security/auth/login/modules/JaasModularClientTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/javax/security/auth/login/modules/JaasModularClientTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -59,8 +59,7 @@
     private static final Path C_SRC = SRC.resolve("JaasClient.java");
     private static final String C_PKG = "client";
     private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
-    private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR
-            + C_PKG + AUTO + JAR_EXTN;
+    private static final String MCN_JAR_NAME = MODULAR + C_PKG + "N" + JAR_EXTN;
     private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
 
     private static final Path BUILD_DIR = Paths.get(".").resolve("build");
@@ -68,7 +67,7 @@
     private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
     private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve(
             S_PKG + DESCRIPTOR);
-    private static final Path C_BUILD_DIR = COMPILE_DIR.resolve(C_PKG);
+    private static final Path C_BLD_DIR = COMPILE_DIR.resolve(C_PKG);
     private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
     private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
 
@@ -83,8 +82,7 @@
     private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
     private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
     private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
-    private static final Path MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR
-            .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME);
+    private static final Path MCN_JAR = C_ARTIFACTS_DIR.resolve(MCN_JAR_NAME);
 
     private static final String MAIN = C_PKG + ".JaasClient";
     private static final String S_INTERFACE
@@ -99,10 +97,7 @@
 
     private static final boolean WITH_S_DESCR = true;
     private static final boolean WITHOUT_S_DESCR = false;
-    private static final String LOGIN_MODULE_NOT_FOUND_MSG
-            = "No LoginModule found";
     private static final String NO_FAILURE = null;
-    private static final Map<String, String> VM_ARGS = new LinkedHashMap<>();
 
     /**
      * Generates Test specific input parameters.
@@ -112,10 +107,10 @@
 
         List<List<Object>> params = new ArrayList<>();
         String[] args = new String[]{};
-        //PARAMETER ORDERS -
-        //client Module Type, Service Module Type,
-        //Service META Descriptor Required,
-        //Expected Failure message, mechanism used to find the provider
+        // PARAMETER ORDERS -
+        // Client Module Type, Service Module Type,
+        // If Service META descriptor Required,
+        // Expected Failure message, Client arguments
         params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
                 WITH_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
@@ -123,7 +118,7 @@
         params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
                 WITH_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
-                WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+                WITHOUT_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
                 WITH_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
@@ -136,7 +131,7 @@
         params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
                 WITH_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
-                WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+                WITHOUT_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
                 WITH_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
@@ -149,7 +144,7 @@
         params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
                 WITH_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
-                WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+                WITHOUT_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
                 WITH_S_DESCR, NO_FAILURE, args));
         params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
@@ -166,29 +161,25 @@
 
         boolean done = true;
         try {
-            VM_ARGS.put("-Duser.language=", "en");
-            VM_ARGS.put("-Duser.region", "US");
-            VM_ARGS.put("-Djava.security.auth.login.config=", SRC.resolve(
-                    "jaas.conf").toFile().getCanonicalPath());
-
             done = CompilerUtils.compile(S_SRC, S_BUILD_DIR);
             done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR);
             done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL);
-            //Generate regular/modular jars with(out) META-INF
-            //service descriptor
+            // Generate modular/regular jars with(out) META-INF
+            // service descriptor
             generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
             generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR,
                     S_WITH_META_DESCR_BUILD_DIR, false);
             generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
             generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR,
                     S_WITH_META_DESCR_BUILD_DIR, false);
-            //Generate regular/modular(depends on explicit/auto service)
-            //jars for client
-            done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR);
-            generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true);
-            generateJar(false, MODULE_TYPE.EXPLICIT,
-                    MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false);
-            generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false);
+            // Compile client source codes.
+            done &= CompilerUtils.compile(C_SRC, C_BLD_DIR);
+            // Generate modular client jar with explicit dependency
+            generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BLD_DIR, true);
+            // Generate modular client jar without any dependency
+            generateJar(false, MODULE_TYPE.EXPLICIT, MCN_JAR, C_BLD_DIR, false);
+            // Generate regular client jar
+            generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BLD_DIR, false);
             System.out.format("%nArtifacts generated successfully? %s", done);
             if (!done) {
                 throw new RuntimeException("Artifact generation failed");
@@ -226,9 +217,9 @@
 
         OutputAnalyzer output = null;
         try {
-            //For automated/explicit module type copy the corresponding
-            //jars to module base folder, which will be considered as
-            //module base path during execution.
+            // For automated/explicit module types, copy the corresponding
+            // jars to module base folder, which will be considered as
+            // module base path during execution.
             if (!(cModuleType == MODULE_TYPE.UNNAMED
                     && sModuletype == MODULE_TYPE.UNNAMED)) {
                 copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
@@ -237,20 +228,19 @@
 
             System.out.format("%nExecuting java client with required"
                     + " custom service in class/module path.");
-            String mName = getModuleName(cModuleType, cJarPath,
-                    C_PKG);
+            String mName = getModuleName(cModuleType, cJarPath, C_PKG);
             Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED
                     || sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null;
             String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
                     sJarPath);
+            Map<String, String> vmArgs = getVMArgs(sModuletype,
+                    getModuleName(sModuletype, sJarPath, S_PKG));
             output = ProcessTools.executeTestJava(
-                    getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS,
+                    getJavaCommand(cmBasePath, cPath, mName, MAIN, vmArgs,
                             args)).outputTo(System.out).errorTo(System.out);
         } finally {
-            //clean module path so that the modulepath can hold only
-            //the required jars for next run.
+            // Clean module path to hold required jars for next run.
             cleanModuleBasePath(M_BASE_PATH);
-            System.out.println("--------------------------------------------");
         }
         return output;
     }
@@ -260,9 +250,9 @@
      * based on client/service module type.
      */
     @Override
-    public Path findJarPath(boolean service, MODULE_TYPE moduleType,
+    public Path findJarPath(boolean isService, MODULE_TYPE moduleType,
             boolean addMetaDesc, boolean dependsOnServiceModule) {
-        if (service) {
+        if (isService) {
             if (moduleType == MODULE_TYPE.EXPLICIT) {
                 if (addMetaDesc) {
                     return MS_WITH_DESCR_JAR;
@@ -277,11 +267,12 @@
                 }
             }
         } else {
+            // Choose corresponding client jar using dependent module
             if (moduleType == MODULE_TYPE.EXPLICIT) {
                 if (dependsOnServiceModule) {
                     return MC_JAR;
                 } else {
-                    return MC_DEPENDS_ON_AUTO_SERVICE_JAR;
+                    return MCN_JAR;
                 }
             } else {
                 return C_JAR;
@@ -289,4 +280,20 @@
         }
     }
 
+    /**
+     * VM argument required for the test.
+     */
+    private Map<String, String> getVMArgs(MODULE_TYPE sModuletype,
+            String addModName) throws IOException {
+        final Map<String, String> vmArgs = new LinkedHashMap<>();
+        vmArgs.put("-Duser.language=", "en");
+        vmArgs.put("-Duser.region=", "US");
+        vmArgs.put("-Djava.security.auth.login.config=", SRC.resolve(
+                "jaas.conf").toFile().getCanonicalPath());
+        if (addModName != null && sModuletype == MODULE_TYPE.AUTO) {
+            vmArgs.put("-addmods ", addModName);
+        }
+        return vmArgs;
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/security/auth/login/modules/JaasModularDefaultHandlerTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Arrays;
+import java.io.IOException;
+import java.lang.module.ModuleDescriptor;
+import java.util.ArrayList;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.OutputAnalyzer;
+import org.testng.annotations.BeforeTest;
+
+/**
+ * @test
+ * @bug 8151654
+ * @library /lib/testlibrary
+ * @library /java/security/modules
+ * @build CompilerUtils JarUtils
+ * @summary Test custom JAAS callback handler with all possible modular option.
+ * @run testng JaasModularDefaultHandlerTest
+ */
+public class JaasModularDefaultHandlerTest extends ModularTest {
+
+    private static final Path S_SRC = SRC.resolve("TestCallbackHandler.java");
+    private static final String MODULAR = "M";
+    private static final String S_PKG = "handler";
+    private static final String S_JAR_NAME = S_PKG + JAR_EXTN;
+    private static final String MS_JAR_NAME = MODULAR + S_PKG + JAR_EXTN;
+    private static final String HANDLER = S_PKG + ".TestCallbackHandler";
+
+    private static final Path C_SRC
+            = SRC.resolve("JaasClientWithDefaultHandler.java");
+    private static final Path CL_SRC = SRC.resolve("TestLoginModule.java");
+    private static final String C_PKG = "login";
+    private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
+    private static final String MCN_JAR_NAME
+            = MODULAR + C_PKG + "NoMUse" + JAR_EXTN;
+    private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
+
+    private static final Path BUILD_DIR = Paths.get(".").resolve("build");
+    private static final Path COMPILE_DIR = BUILD_DIR.resolve("bin");
+    private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
+    private static final Path C_BLD_DIR = COMPILE_DIR.resolve(C_PKG);
+    private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
+    private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
+
+    private static final Path S_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(S_PKG);
+    private static final Path S_JAR = S_ARTIFACTS_DIR.resolve(S_JAR_NAME);
+    private static final Path MS_JAR = S_ARTIFACTS_DIR.resolve(MS_JAR_NAME);
+
+    private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
+    private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
+    private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
+    private static final Path MCN_JAR = C_ARTIFACTS_DIR.resolve(MCN_JAR_NAME);
+
+    private static final String MAIN = C_PKG + ".JaasClientWithDefaultHandler";
+    private static final List<String> M_REQUIRED = Arrays.asList("java.base",
+            "jdk.security.auth");
+
+    private static final String CLASS_NOT_FOUND_MSG
+            = "java.lang.ClassNotFoundException: handler.TestCallbackHandler";
+    private static final String NO_FAILURE = null;
+
+    /**
+     * Generates Test specific input parameters.
+     */
+    @Override
+    public Object[][] getTestInput() {
+
+        List<List<Object>> params = new ArrayList<>();
+        String[] args = new String[]{HANDLER};
+        // PARAMETER ORDERS -
+        // Client Module Type, Service Module Type,
+        // Service META Descriptor Required,
+        // Expected Failure message, Client arguments
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
+                false, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
+                false, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
+                false, NO_FAILURE, args));
+
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
+                false, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
+                false, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
+                false, NO_FAILURE, args));
+
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
+                false, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
+                false, NO_FAILURE, args));
+        params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
+                false, NO_FAILURE, args));
+        return params.stream().map(p -> p.toArray()).toArray(Object[][]::new);
+    }
+
+    /**
+     * Pre-compile and generate the artifacts required to run this test before
+     * running each test cases.
+     */
+    @BeforeTest
+    public void buildArtifacts() {
+
+        boolean done = true;
+        try {
+            done = CompilerUtils.compile(S_SRC, S_BUILD_DIR);
+            // Generate modular/regular handler jars.
+            generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
+            generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
+            // Compile client source codes.
+            done &= CompilerUtils.compile(C_SRC, C_BLD_DIR);
+            done &= CompilerUtils.compile(CL_SRC, C_BLD_DIR);
+            // Generate modular client jar with explicit dependency
+            generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BLD_DIR, true);
+            // Generate modular client jar without any dependency
+            generateJar(false, MODULE_TYPE.EXPLICIT, MCN_JAR, C_BLD_DIR, false);
+            // Generate regular client jar
+            generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BLD_DIR, false);
+            System.out.format("%nArtifacts generated successfully? %s", done);
+            if (!done) {
+                throw new RuntimeException("Artifact generation failed");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Generate modular/regular jar based on module type for this test.
+     */
+    private void generateJar(boolean isService, MODULE_TYPE moduleType,
+            Path jar, Path compilePath, boolean depends) throws IOException {
+
+        ModuleDescriptor mDescriptor = null;
+        if (isService) {
+            mDescriptor = generateModuleDescriptor(isService, moduleType, S_PKG,
+                    S_PKG, null, null, null, M_REQUIRED, depends);
+        } else {
+            mDescriptor = generateModuleDescriptor(isService, moduleType, C_PKG,
+                    C_PKG, null, null, S_PKG, M_REQUIRED, depends);
+        }
+        generateJar(mDescriptor, jar, compilePath);
+    }
+
+    /**
+     * Holds Logic for the test client. This method will get called with each
+     * test parameter.
+     */
+    @Override
+    public OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType,
+            Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath,
+            String... args) throws Exception {
+
+        OutputAnalyzer output = null;
+        try {
+            // For automated/explicit module types, copy the corresponding
+            // jars to module base folder, which will be considered as
+            // module base path during execution.
+            if (!(cModuleType == MODULE_TYPE.UNNAMED
+                    && sModuletype == MODULE_TYPE.UNNAMED)) {
+                copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
+                copyJarsToModuleBase(sModuletype, sJarPath, M_BASE_PATH);
+            }
+
+            System.out.format("%nExecuting java client with required"
+                    + " custom service in class/module path.");
+            String mName = getModuleName(cModuleType, cJarPath, C_PKG);
+            Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED
+                    || sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null;
+            String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
+                    sJarPath);
+            Map<String, String> vmArgs = getVMArgs(sModuletype, cModuleType,
+                    getModuleName(sModuletype, sJarPath, S_PKG));
+            output = ProcessTools.executeTestJava(
+                    getJavaCommand(cmBasePath, cPath, mName, MAIN, vmArgs,
+                            args)).outputTo(System.out).errorTo(System.out);
+        } finally {
+            // Clean module path to hold required jars for next run.
+            cleanModuleBasePath(M_BASE_PATH);
+        }
+        return output;
+    }
+
+    /**
+     * Decide the pre-generated client/service jar path for each test case
+     * based on client/service module type.
+     */
+    @Override
+    public Path findJarPath(boolean depends, MODULE_TYPE moduleType,
+            boolean addMetaDesc, boolean dependsOnServiceModule) {
+        if (depends) {
+            if (moduleType == MODULE_TYPE.EXPLICIT) {
+                return MS_JAR;
+            } else {
+                return S_JAR;
+            }
+        } else {
+            // Choose corresponding client jar using dependent module
+            if (moduleType == MODULE_TYPE.EXPLICIT) {
+                if (dependsOnServiceModule) {
+                    return MC_JAR;
+                } else {
+                    return MCN_JAR;
+                }
+            } else {
+                return C_JAR;
+            }
+        }
+    }
+
+    /**
+     * VM argument required for the test.
+     */
+    private Map<String, String> getVMArgs(MODULE_TYPE sModuletype,
+            MODULE_TYPE cModuleType, String addModName) throws IOException {
+        final Map<String, String> vmArgs = new LinkedHashMap<>();
+        vmArgs.put("-Duser.language=", "en");
+        vmArgs.put("-Duser.region=", "US");
+        vmArgs.put("-Djava.security.auth.login.config=", SRC.resolve(
+                "jaas.conf").toFile().getCanonicalPath());
+        if (addModName != null
+                && !(cModuleType == MODULE_TYPE.EXPLICIT
+                && sModuletype == MODULE_TYPE.EXPLICIT)) {
+            vmArgs.put("-addmods ", addModName);
+        }
+        return vmArgs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/security/auth/login/modules/TestCallbackHandler.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package handler;
+
+import java.io.IOException;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public class TestCallbackHandler implements CallbackHandler {
+
+    private static final String USER_NAME = "testUser";
+    private static final String PASSWORD = "testPassword";
+
+    @Override
+    public void handle(Callback[] callbacks) throws IOException,
+            UnsupportedCallbackException {
+        System.out.println("TestCallbackHandler will get resolved through"
+                + " auth.login.defaultCallbackHandler property.");
+        for (Callback callback : callbacks) {
+            if (callback instanceof NameCallback) {
+                ((NameCallback) callback).setName(USER_NAME);
+            } else if (callback instanceof PasswordCallback) {
+                ((PasswordCallback) callback).setPassword(
+                        PASSWORD.toCharArray());
+            } else {
+                throw new UnsupportedCallbackException(callback);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/net/ftp/TestFtpClientNameListWithNull.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8022580
+ * @summary "null" should be treated as "current directory" in nameList()
+ * method of FtpClient
+ * @modules java.base/sun.net.ftp
+ * @run main TestFtpClientNameListWithNull
+*/
+
+
+import sun.net.ftp.FtpClient;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+
+public class TestFtpClientNameListWithNull {
+
+    private static volatile boolean commandHasArgs;
+
+    public static void main(String[] args) throws Exception {
+        try (FtpServer server = new FtpServer();
+             FtpClient client = FtpClient.create()) {
+            (new Thread(server)).start();
+            int port = server.getPort();
+            client.connect(new InetSocketAddress("localhost", port));
+            client.nameList(null);
+        } finally {
+            if (commandHasArgs) {
+                throw new RuntimeException("Test failed. NLST shouldn't have " +
+                        "args if nameList parameter is null");
+            }
+        }
+    }
+
+    private static class FtpServer implements AutoCloseable, Runnable {
+        private final ServerSocket serverSocket;
+
+        FtpServer() throws IOException {
+            serverSocket = new ServerSocket(0);
+        }
+
+        public void handleClient(Socket client) throws IOException {
+            boolean done = false;
+            String str;
+
+            client.setSoTimeout(2000);
+            BufferedReader in = new BufferedReader(new InputStreamReader(client.
+                    getInputStream()));
+            PrintWriter out = new PrintWriter(client.getOutputStream(), true);
+            out.println("220 FTP serverSocket is ready.");
+            while (!done) {
+                try {
+                    str = in.readLine();
+                } catch (SocketException e) {
+                    done = true;
+                    continue;
+                }
+                String cmd = str.substring(0, str.indexOf(" ") > 0 ?
+                        str.indexOf(" ") : str.length());
+                String args = (cmd.equals(str)) ?
+                        "" : str.substring(str.indexOf(" "));
+                switch (cmd) {
+                    case "QUIT":
+                        out.println("221 Goodbye.");
+                        out.flush();
+                        done = true;
+                        break;
+                    case "EPSV":
+                        if ("all".equalsIgnoreCase(args)) {
+                            out.println("200 EPSV ALL command successful.");
+                            continue;
+                        }
+                        out.println("229 Entering Extended Passive Mode " +
+                                "(|||" + getPort() + "|)");
+                        break;
+                    case "NLST":
+                        if (args.trim().length() != 0) {
+                            commandHasArgs = true;
+                        }
+                        out.println("200 Command okay.");
+                        break;
+                    default:
+                        out.println("500 unsupported command: " + str);
+                }
+            }
+        }
+
+        public int getPort() {
+            if (serverSocket != null) {
+                return serverSocket.getLocalPort();
+            }
+            return 0;
+        }
+
+        public void close() throws IOException {
+            if (serverSocket != null && !serverSocket.isClosed()) {
+                serverSocket.close();
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                try (Socket client = serverSocket.accept()) {
+                    handleClient(client);
+                }
+            } catch (IOException e) {
+                throw new RuntimeException("Problem in test execution", e);
+            }
+        }
+    }
+}
--- a/jdk/test/sun/tools/jps/JpsBase.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/sun/tools/jps/JpsBase.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,17 @@
         return JpsBase.class.getName();
     }
 
+    private static boolean userDirSanityCheck(String fullProcessName) {
+        String userDir = System.getProperty("user.dir");
+        if (!fullProcessName.startsWith(userDir)) {
+            System.err.printf("Test skipped. user.dir '%s' is not a prefix of '%s'\n", userDir, fullProcessName);
+            return false;
+        }
+        return true;
+    }
+
     public static void main(String[] args) throws Exception {
+        System.out.printf("INFO: user.dir:  '%s''\n", System.getProperty("user.dir"));
         long pid = ProcessTools.getProcessId();
 
         List<List<JpsHelper.JpsArg>> combinations = JpsHelper.JpsArg.generateCombinations();
@@ -85,8 +95,12 @@
                     // 30673 /tmp/jtreg/jtreg-workdir/scratch/JpsBase.jar ...
                     isFull = true;
                     String fullProcessName = getFullProcessName();
-                    pattern = "^" + pid + "\\s+" + replaceSpecialChars(fullProcessName) + ".*";
-                    output.shouldMatch(pattern);
+                    // Skip the test if user.dir is not a prefix of the current path
+                    // It's possible if the test is run from symlinked dir or windows alias drive
+                    if (userDirSanityCheck(fullProcessName)) {
+                        pattern = "^" + pid + "\\s+" + replaceSpecialChars(fullProcessName) + ".*";
+                        output.shouldMatch(pattern);
+                    }
                     break;
                 case m:
                     // If '-m' is specified output should contain the arguments passed to the main method:
--- a/jdk/test/sun/tools/jps/TestJpsJar.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/sun/tools/jps/TestJpsJar.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,6 +52,7 @@
         cmd.addAll(JpsHelper.getVmArgs());
         cmd.add("-Dtest.jdk=" + testJdk);
         cmd.add("-Dtest.src=" + testSrc);
+        cmd.add("-Duser.dir=" + System.getProperty("user.dir"));
         cmd.add("-jar");
         cmd.add(jar.getAbsolutePath());
         cmd.add("monkey");
--- a/jdk/test/tools/jimage/JImageToolTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/tools/jimage/JImageToolTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -63,6 +63,8 @@
             String jimage = jimagePath.toAbsolutePath().toString();
             String bootimage = modulesimagePath.toAbsolutePath().toString();
             String extractDir = Paths.get(".", "extract").toAbsolutePath().toString();
+            jimage("list", bootimage);
+            jimage("verify", bootimage);
             jimage("extract", "--dir", extractDir, bootimage);
             System.out.println("Test successful");
          } else {
--- a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -90,6 +90,71 @@
             "",
         },
 
+        // Asterisk works exactly the same as above
+        {
+            "*",
+            "jdk.localedata",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"),
+            List.of(),
+            Arrays.stream(Locale.getAvailableLocales())
+                  // "(root)" for Locale.ROOT rather than ""
+                  .map(loc -> loc.equals(Locale.ROOT) ? "(root)" : loc.toString())
+                  .collect(Collectors.toList()),
+            "",
+        },
+
+        // World English/Spanish in Latin America
+        {
+            "--include-locales=en-001,es-419",
+            "jdk.localedata",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_AU.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_es.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_es_AR.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_150.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_AT.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_es.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_es_419.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_es_AR.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"),
+            List.of(
+                "(root)", "en", "en_US", "en_US_POSIX", "en_001", "en_150", "en_AG", "en_AI",
+                "en_AT", "en_AU", "en_BB", "en_BE", "en_BM", "en_BS", "en_BW", "en_BZ",
+                "en_CA", "en_CC", "en_CH", "en_CK", "en_CM", "en_CX", "en_CY", "en_DE",
+                "en_DG", "en_DK", "en_DM", "en_ER", "en_FI", "en_FJ", "en_FK", "en_FM",
+                "en_GB", "en_GD", "en_GG", "en_GH", "en_GI", "en_GM", "en_GY", "en_HK",
+                "en_IE", "en_IL", "en_IM", "en_IN", "en_IO", "en_JE", "en_JM", "en_KE",
+                "en_KI", "en_KN", "en_KY", "en_LC", "en_LR", "en_LS", "en_MG", "en_MO",
+                "en_MS", "en_MT", "en_MU", "en_MW", "en_MY", "en_NA", "en_NF", "en_NG",
+                "en_NL", "en_NR", "en_NU", "en_NZ", "en_PG", "en_PH", "en_PK", "en_PN",
+                "en_PW", "en_RW", "en_SB", "en_SC", "en_SD", "en_SE", "en_SG", "en_SH",
+                "en_SI", "en_SL", "en_SS", "en_SX", "en_SZ", "en_TC", "en_TK", "en_TO",
+                "en_TT", "en_TV", "en_TZ", "en_UG", "en_VC", "en_VG", "en_VU", "en_WS",
+                "en_ZA", "en_ZM", "en_ZW", "es", "es_419", "es_AR", "es_BO", "es_BR",
+                "es_CL", "es_CO", "es_CR", "es_CU", "es_DO", "es_EC", "es_GT", "es_HN",
+                "es_MX", "es_NI", "es_PA", "es_PE", "es_PR", "es_PY", "es_SV", "es_US",
+                "es_UY", "es_VE"),
+            "",
+        },
+
         // All English and Japanese locales
         {
             "--include-locales=en,ja",
@@ -128,6 +193,35 @@
             "",
         },
 
+        // All locales in Austria
+        {
+            "--include-locales=*-AT",
+            "jdk.localedata",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_de.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_de_AT.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_de.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_de_AT.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_150.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_AT.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"),
+            List.of(
+                "(root)", "en", "en_US", "en_US_POSIX", "en_001", "en_150", "en_AT",
+                "de", "de_AT"),
+            "",
+        },
+
         // All locales in India
         {
             "--include-locales=*-IN",
@@ -154,10 +248,11 @@
                 "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class",
                 "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"),
             List.of(
-                "(root)", "as_IN", "bn_IN", "bo_IN", "brx_IN", "en", /* "en_001", */
-                "en_IN", "en_US", "en_US_POSIX", "gu_IN", "hi_IN", "kn_IN", "kok_IN",
-                "ks_IN", "ml_IN", "mr_IN", "ne_IN", "or_IN", "pa_IN", "pa_IN_#Guru",
-                "ta_IN", "te_IN", "ur_IN"),
+                "(root)", "as_IN", "as", "bn_IN", "bn", "bo_IN", "bo", "brx_IN", "brx",
+                "en", "en_001", "en_IN", "en_US", "en_US_POSIX", "gu_IN", "gu", "hi_IN",
+                "hi", "kn_IN", "kn", "kok_IN", "kok", "ks_IN", "ks", "ml_IN", "ml",
+                "mr_IN", "mr", "ne_IN", "ne", "or_IN", "or", "pa_IN", "pa", "pa_IN_#Guru",
+                "pa__#Guru", "ta_IN", "ta", "te_IN", "te", "ur_IN", "ur"),
             "",
         },
 
@@ -203,12 +298,40 @@
                 "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
                 "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
                 "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh_CN.class",
                 "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
                 "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
                 "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"),
             List.of(
-                "(root)", "en", "en_US", "en_US_POSIX", "zh_HK", "zh_HK_#Hans",
-                "zh_HK_#Hant"),
+                "(root)", "en", "en_US", "en_US_POSIX", "zh", "zh__#Hans", "zh__#Hant",
+                "zh_HK", "zh_HK_#Hans", "zh_HK_#Hant"),
+            "",
+        },
+
+        // Simplified Chinese
+        {
+            "--include-locales=zh-Hans",
+            "jdk.localedata",
+            List.of(
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh_CN.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_zh_SG.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"),
+            List.of(
+                "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/thai_dict",
+                "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
+                "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class",
+                "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"),
+            List.of(
+                "(root)", "en", "en_US", "en_US_POSIX", "zh", "zh__#Hans", "zh_CN",
+                "zh_CN_#Hans", "zh_HK_#Hans", "zh_MO_#Hans", "zh_SG", "zh_SG_#Hans"),
             "",
         },
 
@@ -290,7 +413,7 @@
             null,
             null,
             new PluginException(String.format(
-                PluginsResourceBundle.getMessage("include-locales.invalidtag"), "zh_HK"))
+                PluginsResourceBundle.getMessage("include-locales.invalidtag"), "zh_hk"))
                 .getMessage(),
         },
 
--- a/langtools/.hgtags	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/.hgtags	Wed Jul 05 22:00:06 2017 +0200
@@ -370,3 +370,4 @@
 2d65e127e93d5ff0df61bf78e57d7f46a2f1edeb jdk-9+125
 ea4eea2997b9e2f26cd7965839921710ff4065c8 jdk-9+126
 a42768b48cb0c5af9063e12093975baeeca3b5fa jdk-9+127
+2764986661b6d339ba73af52d69d3506ce12e648 jdk-9+128
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1900,7 +1900,8 @@
             Type qualifier = (tree.meth.hasTag(SELECT))
                     ? ((JCFieldAccess) tree.meth).selected.type
                     : env.enclClass.sym.type;
-            restype = adjustMethodReturnType(qualifier, methName, argtypes, restype);
+            Symbol msym = TreeInfo.symbol(tree.meth);
+            restype = adjustMethodReturnType(msym, qualifier, methName, argtypes, restype);
 
             chk.checkRefTypes(tree.typeargs, typeargtypes);
 
@@ -1912,19 +1913,25 @@
         chk.validate(tree.typeargs, localEnv);
     }
     //where
-        Type adjustMethodReturnType(Type qualifierType, Name methodName, List<Type> argtypes, Type restype) {
-            if (methodName == names.clone && types.isArray(qualifierType)) {
+        Type adjustMethodReturnType(Symbol msym, Type qualifierType, Name methodName, List<Type> argtypes, Type restype) {
+            if (msym != null &&
+                    msym.owner == syms.objectType.tsym &&
+                    methodName == names.getClass &&
+                    argtypes.isEmpty()) {
+                // as a special case, x.getClass() has type Class<? extends |X|>
+                return new ClassType(restype.getEnclosingType(),
+                        List.<Type>of(new WildcardType(types.erasure(qualifierType),
+                                BoundKind.EXTENDS,
+                                syms.boundClass)),
+                        restype.tsym,
+                        restype.getMetadata());
+            } else if (msym != null &&
+                    msym.owner == syms.arrayClass &&
+                    methodName == names.clone &&
+                    types.isArray(qualifierType)) {
                 // as a special case, array.clone() has a result that is
                 // the same as static type of the array being cloned
                 return qualifierType;
-            } else if (methodName == names.getClass && argtypes.isEmpty()) {
-                // as a special case, x.getClass() has type Class<? extends |X|>
-                return new ClassType(restype.getEnclosingType(),
-                              List.<Type>of(new WildcardType(types.erasure(qualifierType),
-                                                               BoundKind.EXTENDS,
-                                                             syms.boundClass)),
-                                     restype.tsym,
-                                     restype.getMetadata());
             } else {
                 return restype;
             }
@@ -2989,7 +2996,7 @@
 
             if (!refType.isErroneous()) {
                 refType = types.createMethodTypeWithReturn(refType,
-                        adjustMethodReturnType(lookupHelper.site, that.name, checkInfo.pt.getParameterTypes(), refType.getReturnType()));
+                        adjustMethodReturnType(refSym, lookupHelper.site, that.name, checkInfo.pt.getParameterTypes(), refType.getReturnType()));
             }
 
             //go ahead with standard method reference compatibility check - note that param check
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Jul 05 22:00:06 2017 +0200
@@ -902,13 +902,7 @@
     /** Return binary operator that corresponds to given access code.
      */
     private OperatorSymbol binaryAccessOperator(int acode) {
-        for (Symbol sym : syms.predefClass.members().getSymbols(NON_RECURSIVE)) {
-            if (sym instanceof OperatorSymbol) {
-                OperatorSymbol op = (OperatorSymbol)sym;
-                if (accessCode(op.opcode) == acode) return op;
-            }
-        }
-        return null;
+        return (OperatorSymbol)operators.lookupBinaryOp(sym -> accessCode(((OperatorSymbol)sym).opcode) == acode);
     }
 
     /** Return tree tag for assignment operation corresponding
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -798,6 +798,15 @@
                     .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_or));
     }
 
+    Symbol lookupBinaryOp(Predicate<Symbol> applicabilityTest) {
+        return binaryOperators.values().stream()
+                .flatMap(List::stream)
+                .map(helper -> helper.doLookup(applicabilityTest))
+                .distinct()
+                .filter(sym -> sym != syms.noSymbol)
+                .findFirst().get();
+    }
+
     /**
      * Complete the initialization of an operator helper by storing it into the corresponding operator map.
      */
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Jul 05 22:00:06 2017 +0200
@@ -449,7 +449,7 @@
             ? CompileState.valueOf(options.get("shouldstop.ifNoError"))
             : CompileState.GENERATE;
 
-        if (options.isUnset("oldDiags"))
+        if (options.isUnset("diags.legacy"))
             log.setDiagnosticFormatter(RichDiagnosticFormatter.instance(context));
 
         PlatformDescription platformProvider = context.get(PlatformDescription.class);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Wed Jul 05 22:00:06 2017 +0200
@@ -346,21 +346,6 @@
         }
     },
 
-    DIAGS("-XDdiags=", null, HIDDEN, INFO) {
-        @Override
-        public boolean process(OptionHelper helper, String option) {
-            option = option.substring(option.indexOf('=') + 1);
-            String diagsOption = option.contains("%") ?
-                "-XDdiagsFormat=" :
-                "-XDdiags=";
-            diagsOption += option;
-            if (XD.matches(diagsOption))
-                return XD.process(helper, diagsOption);
-            else
-                return false;
-        }
-    },
-
     HELP("-help", "opt.help", STANDARD, INFO) {
         @Override
         public boolean process(OptionHelper helper, String option) {
@@ -506,30 +491,6 @@
 
     XDIAGS("-Xdiags:", "opt.diags", EXTENDED, BASIC, ONEOF, "compact", "verbose"),
 
-    /* This is a back door to the compiler's option table.
-     * -XDx=y sets the option x to the value y.
-     * -XDx sets the option x to the value x.
-     */
-    XD("-XD", null, HIDDEN, BASIC) {
-        @Override
-        public boolean matches(String s) {
-            return s.startsWith(text);
-        }
-        @Override
-        public boolean process(OptionHelper helper, String option) {
-            return process(helper, option, option.substring(text.length()));
-        }
-
-        @Override
-        public boolean process(OptionHelper helper, String option, String arg) {
-            int eq = arg.indexOf('=');
-            String key = (eq < 0) ? arg : arg.substring(0, eq);
-            String value = (eq < 0) ? arg : arg.substring(eq+1);
-            helper.put(key, value);
-            return false;
-        }
-    },
-
     XDEBUG("-Xdebug:", null, HIDDEN, BASIC) {
         @Override
         public boolean process(OptionHelper helper, String option) {
@@ -556,6 +517,37 @@
         }
     },
 
+    DIAGS("-diags:", null, HIDDEN, BASIC, true) {
+        @Override
+        public boolean process(OptionHelper helper, String option) {
+            return HiddenGroup.DIAGS.process(helper, option);
+        }
+    },
+
+    /* This is a back door to the compiler's option table.
+     * -XDx=y sets the option x to the value y.
+     * -XDx sets the option x to the value x.
+     */
+    XD("-XD", null, HIDDEN, BASIC) {
+        @Override
+        public boolean matches(String s) {
+            return s.startsWith(text);
+        }
+        @Override
+        public boolean process(OptionHelper helper, String option) {
+            return process(helper, option, option.substring(text.length()));
+        }
+
+        @Override
+        public boolean process(OptionHelper helper, String option, String arg) {
+            int eq = arg.indexOf('=');
+            String key = (eq < 0) ? arg : arg.substring(0, eq);
+            String value = (eq < 0) ? arg : arg.substring(eq+1);
+            helper.put(key, value);
+            return false;
+        }
+    },
+
     XADDEXPORTS("-XaddExports:", "opt.arg.addExports", "opt.addExports", EXTENDED, BASIC) {
         @Override
         public boolean process(OptionHelper helper, String option) {
@@ -672,6 +664,26 @@
         ANYOF
     }
 
+    enum HiddenGroup {
+        DIAGS("diags");
+
+        final String text;
+
+        HiddenGroup(String text) {
+            this.text = text;
+        }
+
+        public boolean process(OptionHelper helper, String option) {
+            String p = option.substring(option.indexOf(':') + 1).trim();
+            String[] subOptions = p.split(";");
+            for (String subOption : subOptions) {
+                subOption = text + "." + subOption.trim();
+                XD.process(helper, subOption, subOption);
+            }
+            return false;
+        }
+    }
+
     public final String text;
 
     final OptionKind kind;
@@ -705,6 +717,12 @@
         this(text, null, descrKey, kind, group, null, null, false);
     }
 
+    Option(String text, String descrKey,
+            OptionKind kind, OptionGroup group,
+            boolean doHasSuffix) {
+        this(text, null, descrKey, kind, group, null, null, doHasSuffix);
+    }
+
     Option(String text, String argsNameKey, String descrKey,
             OptionKind kind, OptionGroup group) {
         this(text, argsNameKey, descrKey, kind, group, null, null, false);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -403,13 +403,13 @@
         public SimpleConfiguration(Options options, Set<DiagnosticPart> parts) {
             this(parts);
             String showSource = null;
-            if ((showSource = options.get("showSource")) != null) {
+            if ((showSource = options.get("diags.showSource")) != null) {
                 if (showSource.equals("true"))
                     setVisiblePart(DiagnosticPart.SOURCE, true);
                 else if (showSource.equals("false"))
                     setVisiblePart(DiagnosticPart.SOURCE, false);
             }
-            String diagOpts = options.get("diags");
+            String diagOpts = options.get("diags.formatterOptions");
             if (diagOpts != null) {//override -XDshowSource
                 Collection<String> args = Arrays.asList(diagOpts.split(","));
                 if (args.contains("short")) {
@@ -422,7 +422,7 @@
                     setVisiblePart(DiagnosticPart.SOURCE, false);
             }
             String multiPolicy = null;
-            if ((multiPolicy = options.get("multilinePolicy")) != null) {
+            if ((multiPolicy = options.get("diags.multilinePolicy")) != null) {
                 if (multiPolicy.equals("disabled"))
                     setVisiblePart(DiagnosticPart.SUBDIAGNOSTICS, false);
                 else if (multiPolicy.startsWith("limit:")) {
@@ -447,7 +447,7 @@
                 }
             }
             String showCaret = null;
-            if (((showCaret = options.get("showCaret")) != null) &&
+            if (((showCaret = options.get("diags.showCaret")) != null) &&
                 showCaret.equals("false"))
                     setCaretEnabled(false);
             else
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -229,9 +229,9 @@
                             DiagnosticPart.SOURCE));
             initFormat();
             initIndentation();
-            if (options.isSet("oldDiags"))
+            if (options.isSet("diags.legacy"))
                 initOldFormat();
-            String fmt = options.get("diagsFormat");
+            String fmt = options.get("diags.layout");
             if (fmt != null) {
                 if (fmt.equals("OLD"))
                     initOldFormat();
@@ -239,12 +239,12 @@
                     initFormats(fmt);
             }
             String srcPos = null;
-            if ((((srcPos = options.get("sourcePosition")) != null)) &&
+            if ((((srcPos = options.get("diags.sourcePosition")) != null)) &&
                     srcPos.equals("bottom"))
                     setSourcePosition(SourcePosition.BOTTOM);
             else
                 setSourcePosition(SourcePosition.AFTER_SUMMARY);
-            String indent = options.get("diagsIndentation");
+            String indent = options.get("diags.indent");
             if (indent != null) {
                 String[] levels = indent.split("\\|");
                 try {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -644,7 +644,7 @@
                 EnumSet.of(RichFormatterFeature.SIMPLE_NAMES,
                     RichFormatterFeature.WHERE_CLAUSES,
                     RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
-            String diagOpts = options.get("diags");
+            String diagOpts = options.get("diags.formatterOptions");
             if (diagOpts != null) {
                 for (String args: diagOpts.split(",")) {
                     if (args.equals("-where")) {
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/ClassTracker.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jshell.jdi;
-
-import java.util.HashMap;
-import java.util.Objects;
-import com.sun.jdi.ReferenceType;
-import java.util.List;
-import com.sun.jdi.VirtualMachine;
-
-/**
- * Tracks the state of a class.
- */
-class ClassTracker {
-
-    private final VirtualMachine vm;
-    private final HashMap<String, ClassInfo> map;
-
-    ClassTracker(VirtualMachine vm) {
-        this.vm = vm;
-        this.map = new HashMap<>();
-    }
-
-    /**
-     * Associates a class name, class bytes, and ReferenceType.
-     */
-    class ClassInfo {
-
-        // The name of the class -- always set
-        private final String className;
-
-        // The corresponding compiled class bytes when a load or redefine
-        // is started.  May not be the loaded bytes.  May be null.
-        private byte[] bytes;
-
-        // The class bytes successfully loaded/redefined into the remote VM.
-        private byte[] loadedBytes;
-
-        // The corresponding JDI ReferenceType.  Used by redefineClasses and
-        // acts as indicator of successful load (null if not loaded).
-        private ReferenceType rt;
-
-        private ClassInfo(String className) {
-            this.className = className;
-        }
-
-        String getClassName() {
-            return className;
-        }
-
-        byte[] getLoadedBytes() {
-            return loadedBytes;
-        }
-
-        byte[] getBytes() {
-            return bytes;
-        }
-
-        private void setBytes(byte[] potentialBytes) {
-            this.bytes = potentialBytes;
-        }
-
-        // The class has been successful loaded redefined.  The class bytes
-        // sent are now actually loaded.
-        void markLoaded() {
-            loadedBytes = bytes;
-        }
-
-        // Ask JDI for the ReferenceType, null if not loaded.
-        ReferenceType getReferenceTypeOrNull() {
-            if (rt == null) {
-                rt = nameToRef(className);
-            }
-            return rt;
-        }
-
-        private ReferenceType nameToRef(String name) {
-            List<ReferenceType> rtl = vm.classesByName(name);
-            if (rtl.size() != 1) {
-                return null;
-            }
-            return rtl.get(0);
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            return o instanceof ClassInfo
-                    && ((ClassInfo) o).className.equals(className);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(this.className);
-        }
-    }
-
-    // Map a class name to the current compiled class bytes.
-    ClassInfo classInfo(String className, byte[] bytes) {
-        ClassInfo ci = get(className);
-        ci.setBytes(bytes);
-        return ci;
-    }
-
-    // Lookup the ClassInfo by class name, create if it does not exist.
-    ClassInfo get(String className) {
-        return map.computeIfAbsent(className, k -> new ClassInfo(k));
-    }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/FailOverExecutionControl.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jshell.jdi;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import jdk.internal.jshell.debug.InternalDebugControl;
-import jdk.jshell.JShellException;
-import jdk.jshell.spi.ExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
-
-/**
- * A meta implementation of ExecutionControl which cycles through the specified
- * ExecutionControl instances until it finds one that starts.
- */
-public class FailOverExecutionControl implements ExecutionControl {
-
-    private final List<ExecutionControl> ecl = new ArrayList<>();
-    private ExecutionControl active = null;
-    private final List<Exception> thrown = new ArrayList<>();
-
-    /**
-     * Create the ExecutionControl instance with at least one actual
-     * ExecutionControl instance.
-     *
-     * @param ec0 the first instance to try
-     * @param ecs the second and on instance to try
-     */
-    public FailOverExecutionControl(ExecutionControl ec0, ExecutionControl... ecs) {
-        ecl.add(ec0);
-        for (ExecutionControl ec : ecs) {
-            ecl.add(ec);
-        }
-    }
-
-    @Override
-    public void start(ExecutionEnv env) throws Exception {
-        for (ExecutionControl ec : ecl) {
-            try {
-                ec.start(env);
-                // Success! This is our active ExecutionControl
-                active = ec;
-                return;
-            } catch (Exception ex) {
-                thrown.add(ex);
-            } catch (Throwable ex) {
-                thrown.add(new RuntimeException(ex));
-            }
-            InternalDebugControl.debug(env.state(), env.userErr(),
-                    thrown.get(thrown.size() - 1), "failed one in FailOverExecutionControl");
-        }
-        // They have all failed -- rethrow the first exception we encountered
-        throw thrown.get(0);
-    }
-
-    @Override
-    public void close() {
-        active.close();
-    }
-
-    @Override
-    public boolean addToClasspath(String path) {
-        return active.addToClasspath(path);
-    }
-
-    @Override
-    public String invoke(String classname, String methodname) throws JShellException {
-        return active.invoke(classname, methodname);
-    }
-
-    @Override
-    public boolean load(Collection<String> classes) {
-        return active.load(classes);
-    }
-
-    @Override
-    public boolean redefine(Collection<String> classes) {
-        return active.redefine(classes);
-    }
-
-    @Override
-    public ClassStatus getClassStatus(String classname) {
-        return active.getClassStatus(classname);
-    }
-
-    @Override
-    public void stop() {
-        active.stop();
-    }
-
-    @Override
-    public String varValue(String classname, String varname) {
-        return active.varValue(classname, varname);
-    }
-
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIConnection.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +0,0 @@
-/*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This source code is provided to illustrate the usage of a given feature
- * or technique and has been deliberately simplified. Additional steps
- * required for a production-quality application, such as security checks,
- * input validation and proper error handling, might not be present in
- * this sample code.
- */
-
-
-package jdk.internal.jshell.jdi;
-
-import com.sun.jdi.*;
-import com.sun.jdi.connect.*;
-
-import java.util.*;
-import java.util.Map.Entry;
-import java.io.*;
-import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
-
-/**
- * Connection to a Java Debug Interface VirtualMachine instance.
- * Adapted from jdb VMConnection. Message handling, exception handling, and I/O
- * redirection changed.  Interface to JShell added.
- */
-class JDIConnection {
-
-    private static final String REMOTE_AGENT = "jdk.internal.jshell.remote.RemoteAgent";
-
-    private VirtualMachine vm;
-    private boolean active = true;
-    private Process process = null;
-    private int outputCompleteCount = 0;
-
-    private final JDIExecutionControl ec;
-    private final Connector connector;
-    private final Map<String, com.sun.jdi.connect.Connector.Argument> connectorArgs;
-    private final int traceFlags;
-
-    private synchronized void notifyOutputComplete() {
-        outputCompleteCount++;
-        notifyAll();
-    }
-
-    private synchronized void waitOutputComplete() {
-        // Wait for stderr and stdout
-        if (process != null) {
-            while (outputCompleteCount < 2) {
-                try {wait();} catch (InterruptedException e) {}
-            }
-        }
-    }
-
-    private Connector findConnector(String name) {
-        for (Connector cntor :
-                 Bootstrap.virtualMachineManager().allConnectors()) {
-            if (cntor.name().equals(name)) {
-                return cntor;
-            }
-        }
-        return null;
-    }
-
-    private Map <String, Connector.Argument> mergeConnectorArgs(Connector connector, Map<String, String> argumentName2Value) {
-        Map<String, Connector.Argument> arguments = connector.defaultArguments();
-
-        for (Entry<String, String> argumentEntry : argumentName2Value.entrySet()) {
-            String name = argumentEntry.getKey();
-            String value = argumentEntry.getValue();
-            Connector.Argument argument = arguments.get(name);
-
-            if (argument == null) {
-                throw new IllegalArgumentException("Argument is not defined for connector:" +
-                                          name + " -- " + connector.name());
-            }
-
-            argument.setValue(value);
-        }
-
-        return arguments;
-    }
-
-    /**
-     * The JShell specific Connector args for the LaunchingConnector.
-     *
-     * @param portthe socket port for (non-JDI) commands
-     * @param remoteVMOptions any user requested VM options
-     * @return the argument map
-     */
-    private static Map<String, String> launchArgs(int port, String remoteVMOptions) {
-        Map<String, String> argumentName2Value = new HashMap<>();
-        argumentName2Value.put("main", REMOTE_AGENT + " " + port);
-        argumentName2Value.put("options", remoteVMOptions);
-        return argumentName2Value;
-    }
-
-    /**
-     * Start the remote agent and establish a JDI connection to it.
-     *
-     * @param ec the execution control instance
-     * @param port the socket port for (non-JDI) commands
-     * @param remoteVMOptions any user requested VM options
-     * @param isLaunch does JDI do the launch? That is, LaunchingConnector,
-     * otherwise we start explicitly and use ListeningConnector
-     */
-    JDIConnection(JDIExecutionControl ec, int port, List<String> remoteVMOptions, boolean isLaunch) {
-        this(ec,
-                isLaunch
-                        ? "com.sun.jdi.CommandLineLaunch"
-                        : "com.sun.jdi.SocketListen",
-                isLaunch
-                        ? launchArgs(port, String.join(" ", remoteVMOptions))
-                        : new HashMap<>(),
-                0);
-        if (isLaunch) {
-            vm = launchTarget();
-        } else {
-            vm = listenTarget(port, remoteVMOptions);
-        }
-
-        if (isOpen() && vm().canBeModified()) {
-            /*
-             * Connection opened on startup.
-             */
-            new JDIEventHandler(vm(), (b) -> ec.handleVMExit())
-                    .start();
-        }
-    }
-
-    /**
-     * Base constructor -- set-up a JDI connection.
-     *
-     * @param ec the execution control instance
-     * @param connectorName the standardized name of the connector
-     * @param argumentName2Value the argument map
-     * @param traceFlags should we trace JDI behavior
-     */
-    JDIConnection(JDIExecutionControl ec, String connectorName, Map<String, String> argumentName2Value, int traceFlags) {
-        this.ec = ec;
-        this.connector = findConnector(connectorName);
-        if (connector == null) {
-            throw new IllegalArgumentException("No connector named: " + connectorName);
-        }
-        connectorArgs = mergeConnectorArgs(connector, argumentName2Value);
-        this.traceFlags = traceFlags;
-    }
-
-    final synchronized VirtualMachine vm() {
-        if (vm == null) {
-            throw new JDINotConnectedException();
-        } else {
-            return vm;
-        }
-    }
-
-    private synchronized boolean isOpen() {
-        return (vm != null);
-    }
-
-    synchronized boolean isRunning() {
-        return process != null && process.isAlive();
-    }
-
-    // Beginning shutdown, ignore any random dying squeals
-    void beginShutdown() {
-        active = false;
-    }
-
-    synchronized void disposeVM() {
-        try {
-            if (vm != null) {
-                vm.dispose(); // This could NPE, so it is caught below
-                vm = null;
-            }
-        } catch (VMDisconnectedException ex) {
-            // Ignore if already closed
-        } catch (Throwable e) {
-            ec.debug(DBG_GEN, null, "disposeVM threw: " + e);
-        } finally {
-            if (process != null) {
-                process.destroy();
-                process = null;
-            }
-            waitOutputComplete();
-        }
-    }
-
-    private void dumpStream(InputStream inStream, final PrintStream pStream) throws IOException {
-        BufferedReader in =
-            new BufferedReader(new InputStreamReader(inStream));
-        int i;
-        try {
-            while ((i = in.read()) != -1) {
-                // directly copy input to output, but skip if asked to close
-                if (active) {
-                    pStream.print((char) i);
-                }
-            }
-        } catch (IOException ex) {
-            String s = ex.getMessage();
-            if (active && !s.startsWith("Bad file number")) {
-                throw ex;
-            }
-            // else we are being shutdown (and don't want any spurious death
-            // throws to ripple) or
-            // we got a Bad file number IOException which just means
-            // that the debuggee has gone away.  We'll just treat it the
-            // same as if we got an EOF.
-        }
-    }
-
-    /**
-     *  Create a Thread that will retrieve and display any output.
-     *  Needs to be high priority, else debugger may exit before
-     *  it can be displayed.
-     */
-    private void displayRemoteOutput(final InputStream inStream, final PrintStream pStream) {
-        Thread thr = new Thread("output reader") {
-            @Override
-            public void run() {
-                try {
-                    dumpStream(inStream, pStream);
-                } catch (IOException ex) {
-                    ec.debug(ex, "Failed reading output");
-                    ec.handleVMExit();
-                } finally {
-                    notifyOutputComplete();
-                }
-            }
-        };
-        thr.setPriority(Thread.MAX_PRIORITY-1);
-        thr.start();
-    }
-
-    /**
-     *  Create a Thread that will ship all input to remote.
-     *  Does it need be high priority?
-     */
-    private void readRemoteInput(final OutputStream outStream, final InputStream inputStream) {
-        Thread thr = new Thread("input reader") {
-            @Override
-            public void run() {
-                try {
-                    byte[] buf = new byte[256];
-                    int cnt;
-                    while ((cnt = inputStream.read(buf)) != -1) {
-                        outStream.write(buf, 0, cnt);
-                        outStream.flush();
-                    }
-                } catch (IOException ex) {
-                    ec.debug(ex, "Failed reading output");
-                    ec.handleVMExit();
-                }
-            }
-        };
-        thr.setPriority(Thread.MAX_PRIORITY-1);
-        thr.start();
-    }
-
-    private void forwardIO() {
-        displayRemoteOutput(process.getErrorStream(), ec.execEnv.userErr());
-        displayRemoteOutput(process.getInputStream(), ec.execEnv.userOut());
-        readRemoteInput(process.getOutputStream(), ec.execEnv.userIn());
-    }
-
-    /* launch child target vm */
-    private VirtualMachine launchTarget() {
-        LaunchingConnector launcher = (LaunchingConnector)connector;
-        try {
-            VirtualMachine new_vm = launcher.launch(connectorArgs);
-            process = new_vm.process();
-            forwardIO();
-            return new_vm;
-        } catch (Exception ex) {
-            reportLaunchFail(ex, "launch");
-        }
-        return null;
-    }
-
-    /**
-     * Directly launch the remote agent and connect JDI to it with a
-     * ListeningConnector.
-     */
-    private VirtualMachine listenTarget(int port, List<String> remoteVMOptions) {
-        ListeningConnector listener = (ListeningConnector) connector;
-        try {
-            // Start listening, get the JDI connection address
-            String addr = listener.startListening(connectorArgs);
-            ec.debug(DBG_GEN, "Listening at address: " + addr);
-
-            // Launch the RemoteAgent requesting a connection on that address
-            String javaHome = System.getProperty("java.home");
-            List<String> args = new ArrayList<>();
-            args.add(javaHome == null
-                    ? "java"
-                    : javaHome + File.separator + "bin" + File.separator + "java");
-            args.add("-agentlib:jdwp=transport=" + connector.transport().name() +
-                    ",address=" + addr);
-            args.addAll(remoteVMOptions);
-            args.add(REMOTE_AGENT);
-            args.add("" + port);
-            ProcessBuilder pb = new ProcessBuilder(args);
-            process = pb.start();
-
-            // Forward out, err, and in
-            forwardIO();
-
-            // Accept the connection from the remote agent
-            vm = listener.accept(connectorArgs);
-            listener.stopListening(connectorArgs);
-            return vm;
-        } catch (Exception ex) {
-            reportLaunchFail(ex, "listen");
-        }
-        return null;
-    }
-
-    private void reportLaunchFail(Exception ex, String context) {
-        throw new InternalError("Failed remote " + context + ": " + connector +
-                " -- " + connectorArgs, ex);
-    }
-}
\ No newline at end of file
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIEventHandler.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.jdi;
-
-import java.util.function.Consumer;
-import com.sun.jdi.*;
-import com.sun.jdi.event.*;
-
-/**
- * Handler of Java Debug Interface events.
- * Adapted from jdb EventHandler; Handling of events not used by JShell stubbed out.
- */
-class JDIEventHandler implements Runnable {
-
-    private final Thread thread;
-    private volatile boolean connected = true;
-    private boolean completed = false;
-    private final VirtualMachine vm;
-    private final Consumer<Boolean> reportVMExit;
-
-    JDIEventHandler(VirtualMachine vm, Consumer<Boolean> reportVMExit) {
-        this.vm = vm;
-        this.reportVMExit = reportVMExit;
-        this.thread = new Thread(this, "event-handler");
-    }
-
-    void start() {
-        thread.start();
-    }
-
-    synchronized void shutdown() {
-        connected = false;  // force run() loop termination
-        thread.interrupt();
-        while (!completed) {
-            try {wait();} catch (InterruptedException exc) {}
-        }
-    }
-
-    @Override
-    public void run() {
-        EventQueue queue = vm.eventQueue();
-        while (connected) {
-            try {
-                EventSet eventSet = queue.remove();
-                boolean resumeStoppedApp = false;
-                EventIterator it = eventSet.eventIterator();
-                while (it.hasNext()) {
-                    resumeStoppedApp |= handleEvent(it.nextEvent());
-                }
-
-                if (resumeStoppedApp) {
-                    eventSet.resume();
-                }
-            } catch (InterruptedException exc) {
-                // Do nothing. Any changes will be seen at top of loop.
-            } catch (VMDisconnectedException discExc) {
-                handleDisconnectedException();
-                break;
-            }
-        }
-        synchronized (this) {
-            completed = true;
-            notifyAll();
-        }
-    }
-
-    private boolean handleEvent(Event event) {
-        if (event instanceof ExceptionEvent) {
-            exceptionEvent(event);
-        } else if (event instanceof WatchpointEvent) {
-            fieldWatchEvent(event);
-        } else if (event instanceof MethodEntryEvent) {
-            methodEntryEvent(event);
-        } else if (event instanceof MethodExitEvent) {
-            methodExitEvent(event);
-        } else if (event instanceof ClassPrepareEvent) {
-            classPrepareEvent(event);
-        } else if (event instanceof ThreadStartEvent) {
-            threadStartEvent(event);
-        } else if (event instanceof ThreadDeathEvent) {
-            threadDeathEvent(event);
-        } else if (event instanceof VMStartEvent) {
-            vmStartEvent(event);
-            return true;
-        } else {
-            handleExitEvent(event);
-        }
-        return true;
-    }
-
-    private boolean vmDied = false;
-
-    private void handleExitEvent(Event event) {
-        if (event instanceof VMDeathEvent) {
-            vmDied = true;
-        } else if (event instanceof VMDisconnectEvent) {
-            connected = false;
-        } else {
-            throw new InternalError("Unexpected event type: " +
-                    event.getClass());
-        }
-        reportVMExit.accept(vmDied);
-    }
-
-    private synchronized void handleDisconnectedException() {
-        /*
-         * A VMDisconnectedException has happened while dealing with
-         * another event. We need to flush the event queue, dealing only
-         * with exit events (VMDeath, VMDisconnect) so that we terminate
-         * correctly.
-         */
-        EventQueue queue = vm.eventQueue();
-        while (connected) {
-            try {
-                EventSet eventSet = queue.remove();
-                EventIterator iter = eventSet.eventIterator();
-                while (iter.hasNext()) {
-                    handleExitEvent(iter.next());
-                }
-            } catch (InterruptedException exc) {
-                // ignore
-            } catch (InternalError exc) {
-                // ignore
-            }
-        }
-    }
-
-    private void vmStartEvent(Event event)  {
-        VMStartEvent se = (VMStartEvent)event;
-    }
-
-    private void methodEntryEvent(Event event)  {
-        MethodEntryEvent me = (MethodEntryEvent)event;
-    }
-
-    private void methodExitEvent(Event event)  {
-        MethodExitEvent me = (MethodExitEvent)event;
-    }
-
-    private void fieldWatchEvent(Event event)  {
-        WatchpointEvent fwe = (WatchpointEvent)event;
-    }
-
-    private void classPrepareEvent(Event event)  {
-        ClassPrepareEvent cle = (ClassPrepareEvent)event;
-    }
-
-    private void exceptionEvent(Event event) {
-        ExceptionEvent ee = (ExceptionEvent)event;
-    }
-
-    private void threadDeathEvent(Event event) {
-        ThreadDeathEvent tee = (ThreadDeathEvent)event;
-    }
-
-    private void threadStartEvent(Event event) {
-        ThreadStartEvent tse = (ThreadStartEvent)event;
-    }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIExecutionControl.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,598 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.jdi;
-
-import static jdk.internal.jshell.remote.RemoteCodes.*;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.PrintStream;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.io.EOFException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import com.sun.jdi.BooleanValue;
-import com.sun.jdi.ClassNotLoadedException;
-import com.sun.jdi.IncompatibleThreadStateException;
-import com.sun.jdi.InvalidTypeException;
-import com.sun.jdi.ObjectReference;
-import com.sun.jdi.ReferenceType;
-import com.sun.jdi.StackFrame;
-import com.sun.jdi.ThreadReference;
-import com.sun.jdi.VirtualMachine;
-import static java.util.stream.Collectors.toList;
-import jdk.jshell.JShellException;
-import jdk.jshell.spi.ExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
-import jdk.internal.jshell.jdi.ClassTracker.ClassInfo;
-import static java.util.stream.Collectors.toMap;
-import jdk.internal.jshell.debug.InternalDebugControl;
-import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
-
-/**
- * Controls the remote execution environment.
- * Interfaces to the JShell-core by implementing ExecutionControl SPI.
- * Interfaces to RemoteAgent over a socket and via JDI.
- * Launches a remote process.
- */
-public class JDIExecutionControl implements ExecutionControl {
-
-    ExecutionEnv execEnv;
-    private final boolean isLaunch;
-    private JDIConnection connection;
-    private ClassTracker classTracker;
-    private Socket socket;
-    private ObjectInputStream remoteIn;
-    private ObjectOutputStream remoteOut;
-
-    /**
-     * Creates an ExecutionControl instance based on JDI.
-     *
-     * @param isLaunch true for LaunchingConnector; false for ListeningConnector
-     */
-    public JDIExecutionControl(boolean isLaunch) {
-        this.isLaunch = isLaunch;
-    }
-
-    /**
-     * Creates an ExecutionControl instance based on a JDI LaunchingConnector.
-     */
-    public JDIExecutionControl() {
-        this.isLaunch = true;
-    }
-
-    /**
-     * Initializes the launching JDI execution engine. Initialize JDI and use it
-     * to launch the remote JVM. Set-up control and result communications socket
-     * to the remote execution environment. This socket also transports the
-     * input/output channels.
-     *
-     * @param execEnv the execution environment provided by the JShell-core
-     * @throws IOException
-     */
-    @Override
-    public void start(ExecutionEnv execEnv) throws IOException {
-        this.execEnv = execEnv;
-        StringBuilder sb = new StringBuilder();
-        try (ServerSocket listener = new ServerSocket(0)) {
-            // timeout after 60 seconds
-            listener.setSoTimeout(60000);
-            int port = listener.getLocalPort();
-            connection = new JDIConnection(this, port, execEnv.extraRemoteVMOptions(), isLaunch);
-            this.socket = listener.accept();
-            // out before in -- match remote creation so we don't hang
-            this.remoteOut = new ObjectOutputStream(socket.getOutputStream());
-            PipeInputStream commandIn = new PipeInputStream();
-            new DemultiplexInput(socket.getInputStream(), commandIn, execEnv.userOut(), execEnv.userErr()).start();
-            this.remoteIn = new ObjectInputStream(commandIn);
-        }
-    }
-
-    /**
-     * Closes the execution engine. Send an exit command to the remote agent.
-     * Shuts down the JDI connection. Should this close the socket?
-     */
-    @Override
-    public void close() {
-        try {
-            if (connection != null) {
-                connection.beginShutdown();
-            }
-            if (remoteOut != null) {
-                remoteOut.writeInt(CMD_EXIT);
-                remoteOut.flush();
-            }
-            if (connection != null) {
-                connection.disposeVM();
-            }
-        } catch (IOException ex) {
-            debug(DBG_GEN, "Exception on JDI exit: %s\n", ex);
-        }
-    }
-
-    /**
-     * Loads the list of classes specified. Sends a load command to the remote
-     * agent with pairs of classname/bytes.
-     *
-     * @param classes the names of the wrapper classes to loaded
-     * @return true if all classes loaded successfully
-     */
-    @Override
-    public boolean load(Collection<String> classes) {
-        try {
-            // Create corresponding ClassInfo instances to track the classes.
-            // Each ClassInfo has the current class bytes associated with it.
-            List<ClassInfo> infos = withBytes(classes);
-            // Send a load command to the remote agent.
-            remoteOut.writeInt(CMD_LOAD);
-            remoteOut.writeInt(classes.size());
-            for (ClassInfo ci : infos) {
-                remoteOut.writeUTF(ci.getClassName());
-                remoteOut.writeObject(ci.getBytes());
-            }
-            remoteOut.flush();
-            // Retrieve and report results from the remote agent.
-            boolean result = readAndReportResult();
-            // For each class that now has a JDI ReferenceType, mark the bytes
-            // as loaded.
-            infos.stream()
-                    .filter(ci -> ci.getReferenceTypeOrNull() != null)
-                    .forEach(ci -> ci.markLoaded());
-            return result;
-        } catch (IOException ex) {
-            debug(DBG_GEN, "IOException on remote load operation: %s\n", ex);
-            return false;
-        }
-    }
-
-    /**
-     * Invoke the doit method on the specified class.
-     *
-     * @param classname name of the wrapper class whose doit should be invoked
-     * @return return the result value of the doit
-     * @throws JShellException if a user exception was thrown (EvalException) or
-     * an unresolved reference was encountered (UnresolvedReferenceException)
-     */
-    @Override
-    public String invoke(String classname, String methodname) throws JShellException {
-        try {
-            synchronized (STOP_LOCK) {
-                userCodeRunning = true;
-            }
-            // Send the invoke command to the remote agent.
-            remoteOut.writeInt(CMD_INVOKE);
-            remoteOut.writeUTF(classname);
-            remoteOut.writeUTF(methodname);
-            remoteOut.flush();
-            // Retrieve and report results from the remote agent.
-            if (readAndReportExecutionResult()) {
-                String result = remoteIn.readUTF();
-                return result;
-            }
-        } catch (IOException | RuntimeException ex) {
-            if (!connection.isRunning()) {
-                // The JDI connection is no longer live, shutdown.
-                handleVMExit();
-            } else {
-                debug(DBG_GEN, "Exception on remote invoke: %s\n", ex);
-                return "Execution failure: " + ex.getMessage();
-            }
-        } finally {
-            synchronized (STOP_LOCK) {
-                userCodeRunning = false;
-            }
-        }
-        return "";
-    }
-
-    /**
-     * Retrieves the value of a JShell variable.
-     *
-     * @param classname name of the wrapper class holding the variable
-     * @param varname name of the variable
-     * @return the value as a String
-     */
-    @Override
-    public String varValue(String classname, String varname) {
-        try {
-            // Send the variable-value command to the remote agent.
-            remoteOut.writeInt(CMD_VARVALUE);
-            remoteOut.writeUTF(classname);
-            remoteOut.writeUTF(varname);
-            remoteOut.flush();
-            // Retrieve and report results from the remote agent.
-            if (readAndReportResult()) {
-                String result = remoteIn.readUTF();
-                return result;
-            }
-        } catch (EOFException ex) {
-            handleVMExit();
-        } catch (IOException ex) {
-            debug(DBG_GEN, "Exception on remote var value: %s\n", ex);
-            return "Execution failure: " + ex.getMessage();
-        }
-        return "";
-    }
-
-    /**
-     * Adds a path to the remote classpath.
-     *
-     * @param cp the additional path element
-     * @return true if succesful
-     */
-    @Override
-    public boolean addToClasspath(String cp) {
-        try {
-            // Send the classpath addition command to the remote agent.
-            remoteOut.writeInt(CMD_CLASSPATH);
-            remoteOut.writeUTF(cp);
-            remoteOut.flush();
-            // Retrieve and report results from the remote agent.
-            return readAndReportResult();
-        } catch (IOException ex) {
-            throw new InternalError("Classpath addition failed: " + cp, ex);
-        }
-    }
-
-    /**
-     * Redefine the specified classes. Where 'redefine' is, as in JDI and JVMTI,
-     * an in-place replacement of the classes (preserving class identity) --
-     * that is, existing references to the class do not need to be recompiled.
-     * This implementation uses JDI redefineClasses. It will be unsuccessful if
-     * the signature of the class has changed (see the JDI spec). The
-     * JShell-core is designed to adapt to unsuccessful redefine.
-     *
-     * @param classes the names of the classes to redefine
-     * @return true if all the classes were redefined
-     */
-    @Override
-    public boolean redefine(Collection<String> classes) {
-        try {
-            // Create corresponding ClassInfo instances to track the classes.
-            // Each ClassInfo has the current class bytes associated with it.
-            List<ClassInfo> infos = withBytes(classes);
-            // Convert to the JDI ReferenceType to class bytes map form needed
-            // by JDI.
-            Map<ReferenceType, byte[]> rmp = infos.stream()
-                    .collect(toMap(
-                            ci -> ci.getReferenceTypeOrNull(),
-                            ci -> ci.getBytes()));
-            // Attempt redefine.  Throws exceptions on failure.
-            connection.vm().redefineClasses(rmp);
-            // Successful: mark the bytes as loaded.
-            infos.stream()
-                    .forEach(ci -> ci.markLoaded());
-            return true;
-        } catch (UnsupportedOperationException ex) {
-            // A form of class transformation not supported by JDI
-            return false;
-        } catch (Exception ex) {
-            debug(DBG_GEN, "Exception on JDI redefine: %s\n", ex);
-            return false;
-        }
-    }
-
-    // the VM has gone down in flames or because user evaled System.exit() or the like
-    void handleVMExit() {
-        if (connection != null) {
-            // If there is anything left dispose of it
-            connection.disposeVM();
-        }
-        // Tell JShell-core that the VM has died
-        execEnv.closeDown();
-    }
-
-    // Lazy init class tracker
-    private ClassTracker classTracker() {
-        if (classTracker == null) {
-            classTracker = new ClassTracker(connection.vm());
-        }
-        return classTracker;
-    }
-
-    /**
-     * Converts a collection of class names into ClassInfo instances associated
-     * with the most recently compiled class bytes.
-     *
-     * @param classes names of the classes
-     * @return a list of corresponding ClassInfo instances
-     */
-    private List<ClassInfo> withBytes(Collection<String> classes) {
-        return classes.stream()
-                .map(cn -> classTracker().classInfo(cn, execEnv.getClassBytes(cn)))
-                .collect(toList());
-    }
-
-    /**
-     * Reports the status of the named class. UNKNOWN if not loaded. CURRENT if
-     * the most recent successfully loaded/redefined bytes match the current
-     * compiled bytes.
-     *
-     * @param classname the name of the class to test
-     * @return the status
-     */
-    @Override
-    public ClassStatus getClassStatus(String classname) {
-        ClassInfo ci = classTracker().get(classname);
-        if (ci.getReferenceTypeOrNull() == null) {
-            // If the class does not have a JDI ReferenceType it has not been loaded
-            return ClassStatus.UNKNOWN;
-        }
-        // Compare successfully loaded with last compiled bytes.
-        return (Arrays.equals(execEnv.getClassBytes(classname), ci.getLoadedBytes()))
-                ? ClassStatus.CURRENT
-                : ClassStatus.NOT_CURRENT;
-    }
-
-    /**
-     * Reports results from a remote agent command that does not expect
-     * exceptions.
-     *
-     * @return true if successful
-     * @throws IOException if the connection has dropped
-     */
-    private boolean readAndReportResult() throws IOException {
-        int ok = remoteIn.readInt();
-        switch (ok) {
-            case RESULT_SUCCESS:
-                return true;
-            case RESULT_FAIL: {
-                String ex = remoteIn.readUTF();
-                debug(DBG_GEN, "Exception on remote operation: %s\n", ex);
-                return false;
-            }
-            default: {
-                debug(DBG_GEN, "Bad remote result code: %s\n", ok);
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Reports results from a remote agent command that expects runtime
-     * exceptions.
-     *
-     * @return true if successful
-     * @throws IOException if the connection has dropped
-     * @throws EvalException if a user exception was encountered on invoke
-     * @throws UnresolvedReferenceException if an unresolved reference was
-     * encountered
-     */
-    private boolean readAndReportExecutionResult() throws IOException, JShellException {
-        int ok = remoteIn.readInt();
-        switch (ok) {
-            case RESULT_SUCCESS:
-                return true;
-            case RESULT_FAIL: {
-                // An internal error has occurred.
-                String ex = remoteIn.readUTF();
-                return false;
-            }
-            case RESULT_EXCEPTION: {
-                // A user exception was encountered.
-                String exceptionClassName = remoteIn.readUTF();
-                String message = remoteIn.readUTF();
-                StackTraceElement[] elems = readStackTrace();
-                throw execEnv.createEvalException(message, exceptionClassName, elems);
-            }
-            case RESULT_CORRALLED: {
-                // An unresolved reference was encountered.
-                int id = remoteIn.readInt();
-                StackTraceElement[] elems = readStackTrace();
-                throw execEnv.createUnresolvedReferenceException(id, elems);
-            }
-            case RESULT_KILLED: {
-                // Execution was aborted by the stop()
-                debug(DBG_GEN, "Killed.");
-                return false;
-            }
-            default: {
-                debug(DBG_GEN, "Bad remote result code: %s\n", ok);
-                return false;
-            }
-        }
-    }
-
-    private StackTraceElement[] readStackTrace() throws IOException {
-        int elemCount = remoteIn.readInt();
-        StackTraceElement[] elems = new StackTraceElement[elemCount];
-        for (int i = 0; i < elemCount; ++i) {
-            String className = remoteIn.readUTF();
-            String methodName = remoteIn.readUTF();
-            String fileName = remoteIn.readUTF();
-            int line = remoteIn.readInt();
-            elems[i] = new StackTraceElement(className, methodName, fileName, line);
-        }
-        return elems;
-    }
-
-    private final Object STOP_LOCK = new Object();
-    private boolean userCodeRunning = false;
-
-    /**
-     * Interrupt a running invoke.
-     */
-    @Override
-    public void stop() {
-        synchronized (STOP_LOCK) {
-            if (!userCodeRunning) {
-                return;
-            }
-
-            VirtualMachine vm = connection.vm();
-            vm.suspend();
-            try {
-                OUTER:
-                for (ThreadReference thread : vm.allThreads()) {
-                    // could also tag the thread (e.g. using name), to find it easier
-                    for (StackFrame frame : thread.frames()) {
-                        String remoteAgentName = "jdk.internal.jshell.remote.RemoteAgent";
-                        if (remoteAgentName.equals(frame.location().declaringType().name())
-                                && "commandLoop".equals(frame.location().method().name())) {
-                            ObjectReference thiz = frame.thisObject();
-                            if (((BooleanValue) thiz.getValue(thiz.referenceType().fieldByName("inClientCode"))).value()) {
-                                thiz.setValue(thiz.referenceType().fieldByName("expectingStop"), vm.mirrorOf(true));
-                                ObjectReference stopInstance = (ObjectReference) thiz.getValue(thiz.referenceType().fieldByName("stopException"));
-
-                                vm.resume();
-                                debug(DBG_GEN, "Attempting to stop the client code...\n");
-                                thread.stop(stopInstance);
-                                thiz.setValue(thiz.referenceType().fieldByName("expectingStop"), vm.mirrorOf(false));
-                            }
-
-                            break OUTER;
-                        }
-                    }
-                }
-            } catch (ClassNotLoadedException | IncompatibleThreadStateException | InvalidTypeException ex) {
-                debug(DBG_GEN, "Exception on remote stop: %s\n", ex);
-            } finally {
-                vm.resume();
-            }
-        }
-    }
-
-    void debug(int flags, String format, Object... args) {
-        InternalDebugControl.debug(execEnv.state(), execEnv.userErr(), flags, format, args);
-    }
-
-    void debug(Exception ex, String where) {
-        InternalDebugControl.debug(execEnv.state(), execEnv.userErr(), ex, where);
-    }
-
-    private final class DemultiplexInput extends Thread {
-
-        private final DataInputStream delegate;
-        private final PipeInputStream command;
-        private final PrintStream out;
-        private final PrintStream err;
-
-        public DemultiplexInput(InputStream input,
-                PipeInputStream command,
-                PrintStream out,
-                PrintStream err) {
-            super("output reader");
-            this.delegate = new DataInputStream(input);
-            this.command = command;
-            this.out = out;
-            this.err = err;
-        }
-
-        public void run() {
-            try {
-                while (true) {
-                    int nameLen = delegate.read();
-                    if (nameLen == (-1))
-                        break;
-                    byte[] name = new byte[nameLen];
-                    DemultiplexInput.this.delegate.readFully(name);
-                    int dataLen = delegate.read();
-                    byte[] data = new byte[dataLen];
-                    DemultiplexInput.this.delegate.readFully(data);
-                    switch (new String(name, "UTF-8")) {
-                        case "err":
-                            err.write(data);
-                            break;
-                        case "out":
-                            out.write(data);
-                            break;
-                        case "command":
-                            for (byte b : data) {
-                                command.write(Byte.toUnsignedInt(b));
-                            }
-                            break;
-                    }
-                }
-            } catch (IOException ex) {
-                debug(ex, "Failed reading output");
-            } finally {
-                command.close();
-            }
-        }
-
-    }
-
-    public static final class PipeInputStream extends InputStream {
-        public static final int INITIAL_SIZE = 128;
-
-        private int[] buffer = new int[INITIAL_SIZE];
-        private int start;
-        private int end;
-        private boolean closed;
-
-        @Override
-        public synchronized int read() {
-            while (start == end) {
-                if (closed) {
-                    return -1;
-                }
-                try {
-                    wait();
-                } catch (InterruptedException ex) {
-                    //ignore
-                }
-            }
-            try {
-                return buffer[start];
-            } finally {
-                start = (start + 1) % buffer.length;
-            }
-        }
-
-        public synchronized void write(int b) {
-            if (closed)
-                throw new IllegalStateException("Already closed.");
-            int newEnd = (end + 1) % buffer.length;
-            if (newEnd == start) {
-                //overflow:
-                int[] newBuffer = new int[buffer.length * 2];
-                int rightPart = (end > start ? end : buffer.length) - start;
-                int leftPart = end > start ? 0 : start - 1;
-                System.arraycopy(buffer, start, newBuffer, 0, rightPart);
-                System.arraycopy(buffer, 0, newBuffer, rightPart, leftPart);
-                buffer = newBuffer;
-                start = 0;
-                end = rightPart + leftPart;
-                newEnd = end + 1;
-            }
-            buffer[end] = b;
-            end = newEnd;
-            notifyAll();
-        }
-
-        @Override
-        public synchronized void close() {
-            closed = true;
-            notifyAll();
-        }
-
-    }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDINotConnectedException.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.jdi;
-
-/**
- * Internal exception when Java Debug Interface VirtualMacine is not connected.
- * Copy of jdb VMNotConnectedException.
- */
-class JDINotConnectedException extends RuntimeException {
-
-    private static final long serialVersionUID = -7433430494903950165L;
-
-    public JDINotConnectedException() {
-        super();
-    }
-
-    public JDINotConnectedException(String s) {
-        super(s);
-    }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,326 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.remote;
-import jdk.jshell.spi.SPIResolutionException;
-import java.io.File;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.Socket;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static jdk.internal.jshell.remote.RemoteCodes.*;
-
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * The remote agent runs in the execution process (separate from the main JShell
- * process.  This agent loads code over a socket from the main JShell process,
- * executes the code, and other misc,
- * @author Robert Field
- */
-class RemoteAgent {
-
-    private final RemoteClassLoader loader = new RemoteClassLoader();
-    private final Map<String, Class<?>> klasses = new TreeMap<>();
-
-    public static void main(String[] args) throws Exception {
-        String loopBack = null;
-        Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
-        (new RemoteAgent()).commandLoop(socket);
-    }
-
-    void commandLoop(Socket socket) throws IOException {
-        // in before out -- so we don't hang the controlling process
-        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
-        OutputStream socketOut = socket.getOutputStream();
-        System.setOut(new PrintStream(new MultiplexingOutputStream("out", socketOut), true));
-        System.setErr(new PrintStream(new MultiplexingOutputStream("err", socketOut), true));
-        ObjectOutputStream out = new ObjectOutputStream(new MultiplexingOutputStream("command", socketOut));
-        while (true) {
-            int cmd = in.readInt();
-            switch (cmd) {
-                case CMD_EXIT:
-                    // Terminate this process
-                    return;
-                case CMD_LOAD:
-                    // Load a generated class file over the wire
-                    try {
-                        int count = in.readInt();
-                        List<String> names = new ArrayList<>(count);
-                        for (int i = 0; i < count; ++i) {
-                            String name = in.readUTF();
-                            byte[] kb = (byte[]) in.readObject();
-                            loader.delare(name, kb);
-                            names.add(name);
-                        }
-                        for (String name : names) {
-                            Class<?> klass = loader.loadClass(name);
-                            klasses.put(name, klass);
-                            // Get class loaded to the point of, at least, preparation
-                            klass.getDeclaredMethods();
-                        }
-                        out.writeInt(RESULT_SUCCESS);
-                        out.flush();
-                    } catch (IOException | ClassNotFoundException | ClassCastException ex) {
-                        debug("*** Load failure: %s\n", ex);
-                        out.writeInt(RESULT_FAIL);
-                        out.writeUTF(ex.toString());
-                        out.flush();
-                    }
-                    break;
-                case CMD_INVOKE: {
-                    // Invoke executable entry point in loaded code
-                    String name = in.readUTF();
-                    Class<?> klass = klasses.get(name);
-                    if (klass == null) {
-                        debug("*** Invoke failure: no such class loaded %s\n", name);
-                        out.writeInt(RESULT_FAIL);
-                        out.writeUTF("no such class loaded: " + name);
-                        out.flush();
-                        break;
-                    }
-                    String methodName = in.readUTF();
-                    Method doitMethod;
-                    try {
-                        this.getClass().getModule().addExports(SPIResolutionException.class.getPackage().getName(), klass.getModule());
-                        doitMethod = klass.getDeclaredMethod(methodName, new Class<?>[0]);
-                        doitMethod.setAccessible(true);
-                        Object res;
-                        try {
-                            clientCodeEnter();
-                            res = doitMethod.invoke(null, new Object[0]);
-                        } catch (InvocationTargetException ex) {
-                            if (ex.getCause() instanceof StopExecutionException) {
-                                expectingStop = false;
-                                throw (StopExecutionException) ex.getCause();
-                            }
-                            throw ex;
-                        } catch (StopExecutionException ex) {
-                            expectingStop = false;
-                            throw ex;
-                        } finally {
-                            clientCodeLeave();
-                        }
-                        out.writeInt(RESULT_SUCCESS);
-                        out.writeUTF(valueString(res));
-                        out.flush();
-                    } catch (InvocationTargetException ex) {
-                        Throwable cause = ex.getCause();
-                        StackTraceElement[] elems = cause.getStackTrace();
-                        if (cause instanceof SPIResolutionException) {
-                            out.writeInt(RESULT_CORRALLED);
-                            out.writeInt(((SPIResolutionException) cause).id());
-                        } else {
-                            out.writeInt(RESULT_EXCEPTION);
-                            out.writeUTF(cause.getClass().getName());
-                            out.writeUTF(cause.getMessage() == null ? "<none>" : cause.getMessage());
-                        }
-                        out.writeInt(elems.length);
-                        for (StackTraceElement ste : elems) {
-                            out.writeUTF(ste.getClassName());
-                            out.writeUTF(ste.getMethodName());
-                            out.writeUTF(ste.getFileName() == null ? "<none>" : ste.getFileName());
-                            out.writeInt(ste.getLineNumber());
-                        }
-                        out.flush();
-                    } catch (NoSuchMethodException | IllegalAccessException ex) {
-                        debug("*** Invoke failure: %s -- %s\n", ex, ex.getCause());
-                        out.writeInt(RESULT_FAIL);
-                        out.writeUTF(ex.toString());
-                        out.flush();
-                    } catch (StopExecutionException ex) {
-                        try {
-                            out.writeInt(RESULT_KILLED);
-                            out.flush();
-                        } catch (IOException err) {
-                            debug("*** Error writing killed result: %s -- %s\n", ex, ex.getCause());
-                        }
-                    }
-                    System.out.flush();
-                    break;
-                }
-                case CMD_VARVALUE: {
-                    // Retrieve a variable value
-                    String classname = in.readUTF();
-                    String varname = in.readUTF();
-                    Class<?> klass = klasses.get(classname);
-                    if (klass == null) {
-                        debug("*** Var value failure: no such class loaded %s\n", classname);
-                        out.writeInt(RESULT_FAIL);
-                        out.writeUTF("no such class loaded: " + classname);
-                        out.flush();
-                        break;
-                    }
-                    try {
-                        Field var = klass.getDeclaredField(varname);
-                        var.setAccessible(true);
-                        Object res = var.get(null);
-                        out.writeInt(RESULT_SUCCESS);
-                        out.writeUTF(valueString(res));
-                        out.flush();
-                    } catch (Exception ex) {
-                        debug("*** Var value failure: no such field %s.%s\n", classname, varname);
-                        out.writeInt(RESULT_FAIL);
-                        out.writeUTF("no such field loaded: " + varname + " in class: " + classname);
-                        out.flush();
-                    }
-                    break;
-                }
-                case CMD_CLASSPATH: {
-                    // Append to the claspath
-                    String cp = in.readUTF();
-                    for (String path : cp.split(File.pathSeparator)) {
-                        loader.addURL(new File(path).toURI().toURL());
-                    }
-                    out.writeInt(RESULT_SUCCESS);
-                    out.flush();
-                    break;
-                }
-                default:
-                    debug("*** Bad command code: %d\n", cmd);
-                    break;
-            }
-        }
-    }
-
-    // These three variables are used by the main JShell process in interrupting
-    // the running process.  Access is via JDI, so the reference is not visible
-    // to code inspection.
-    private boolean inClientCode; // Queried by the main process
-    private boolean expectingStop; // Set by the main process
-
-    // thrown by the main process via JDI:
-    private final StopExecutionException stopException = new StopExecutionException();
-
-    @SuppressWarnings("serial")             // serialVersionUID intentionally omitted
-    private class StopExecutionException extends ThreadDeath {
-        @Override public synchronized Throwable fillInStackTrace() {
-            return this;
-        }
-    }
-
-    void clientCodeEnter() {
-        expectingStop = false;
-        inClientCode = true;
-    }
-
-    void clientCodeLeave() {
-        inClientCode = false;
-        while (expectingStop) {
-            try {
-                Thread.sleep(0);
-            } catch (InterruptedException ex) {
-                debug("*** Sleep interrupted while waiting for stop exception: %s\n", ex);
-            }
-        }
-    }
-
-    private void debug(String format, Object... args) {
-        System.err.printf("REMOTE: "+format, args);
-    }
-
-    static String valueString(Object value) {
-        if (value == null) {
-            return "null";
-        } else if (value instanceof String) {
-            return "\"" + (String)value + "\"";
-        } else if (value instanceof Character) {
-            return "'" + value + "'";
-        } else {
-            return value.toString();
-        }
-    }
-
-    private static final class MultiplexingOutputStream extends OutputStream {
-
-        private static final int PACKET_SIZE = 127;
-
-        private final byte[] name;
-        private final OutputStream delegate;
-
-        public MultiplexingOutputStream(String name, OutputStream delegate) {
-            try {
-                this.name = name.getBytes("UTF-8");
-                this.delegate = delegate;
-            } catch (UnsupportedEncodingException ex) {
-                throw new IllegalStateException(ex); //should not happen
-            }
-        }
-
-        @Override
-        public void write(int b) throws IOException {
-            synchronized (delegate) {
-                delegate.write(name.length); //assuming the len is small enough to fit into byte
-                delegate.write(name);
-                delegate.write(1);
-                delegate.write(b);
-                delegate.flush();
-            }
-        }
-
-        @Override
-        public void write(byte[] b, int off, int len) throws IOException {
-            synchronized (delegate) {
-                int i = 0;
-                while (len > 0) {
-                    int size = Math.min(PACKET_SIZE, len);
-
-                    delegate.write(name.length); //assuming the len is small enough to fit into byte
-                    delegate.write(name);
-                    delegate.write(size);
-                    delegate.write(b, off + i, size);
-                    i += size;
-                    len -= size;
-                }
-
-                delegate.flush();
-            }
-        }
-
-        @Override
-        public void flush() throws IOException {
-            super.flush();
-            delegate.flush();
-        }
-
-        @Override
-        public void close() throws IOException {
-            super.close();
-            delegate.close();
-        }
-
-    }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteClassLoader.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.remote;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.security.CodeSource;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * Class loader wrapper which caches class files by name until requested.
- * @author Robert Field
- */
-class RemoteClassLoader extends URLClassLoader {
-
-    private final Map<String, byte[]> classObjects = new TreeMap<>();
-
-    RemoteClassLoader() {
-        super(new URL[0]);
-    }
-
-    void delare(String name, byte[] bytes) {
-        classObjects.put(name, bytes);
-    }
-
-    @Override
-    protected Class<?> findClass(String name) throws ClassNotFoundException {
-        byte[] b = classObjects.get(name);
-        if (b == null) {
-            return super.findClass(name);
-        }
-        return super.defineClass(name, b, 0, b.length, (CodeSource) null);
-    }
-
-    @Override
-    public void addURL(URL url) {
-        super.addURL(url);
-    }
-
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteCodes.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.remote;
-
-/**
- * Communication constants shared between the main process and the remote
- * execution process
- * @author Robert Field
- */
-public class RemoteCodes {
-    // Command codes
-    public static final int CMD_EXIT       = 0;
-    public static final int CMD_LOAD       = 1;
-    public static final int CMD_INVOKE     = 3;
-    public static final int CMD_CLASSPATH  = 4;
-    public static final int CMD_VARVALUE   = 5;
-
-    // Return result codes
-    public static final int RESULT_SUCCESS   = 100;
-    public static final int RESULT_FAIL      = 101;
-    public static final int RESULT_EXCEPTION = 102;
-    public static final int RESULT_CORRALLED = 103;
-    public static final int RESULT_KILLED    = 104;
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Wed Jul 05 22:00:06 2017 +0200
@@ -233,6 +233,7 @@
     private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
     private static final String[] SHORTCUT_FIXES = {
         "\033\015", //Alt-Enter (Linux)
+        "\033\012", //Alt-Enter (Linux)
         "\033\133\061\067\176", //F6/Alt-F1 (Mac)
         "\u001BO3P" //Alt-F1 (Linux)
     };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ClassTracker.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Objects;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+
+/**
+ * Tracks the state of a class.
+ */
+class ClassTracker {
+
+    private final HashMap<String, ClassInfo> map;
+
+    ClassTracker() {
+        this.map = new HashMap<>();
+    }
+
+    /**
+     * Associates a class name, class bytes (current and loaded).
+     */
+    class ClassInfo {
+
+        // The name of the class
+        private final String className;
+
+        // The corresponding compiled class bytes when a load or redefine
+        // is started.  May not be the loaded bytes.  May be null.
+        private byte[] currentBytes;
+
+        // The class bytes successfully loaded/redefined into the remote VM.
+        private byte[] loadedBytes;
+
+        private ClassInfo(String className) {
+            this.className = className;
+        }
+
+        String getClassName() {
+            return className;
+        }
+
+        byte[] getLoadedBytes() {
+            return loadedBytes;
+        }
+
+        byte[] getCurrentBytes() {
+            return currentBytes;
+        }
+
+        void setCurrentBytes(byte[] bytes) {
+            this.currentBytes = bytes;
+        }
+
+        void setLoadedBytes(byte[] bytes) {
+            this.loadedBytes = bytes;
+        }
+
+        boolean isLoaded() {
+            return loadedBytes != null;
+        }
+
+        boolean isCurrent() {
+            return Arrays.equals(currentBytes, loadedBytes);
+        }
+
+        ClassBytecodes toClassBytecodes() {
+            return new ClassBytecodes(className, currentBytes);
+        }
+
+            @Override
+        public boolean equals(Object o) {
+            return o instanceof ClassInfo
+                    && ((ClassInfo) o).className.equals(className);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(this.className);
+        }
+    }
+
+    void markLoaded(ClassBytecodes[] cbcs) {
+        for (ClassBytecodes cbc : cbcs) {
+            get(cbc.name()).setLoadedBytes(cbc.bytecodes());
+        }
+    }
+
+    void markLoaded(ClassBytecodes[] cbcs, boolean[] isLoaded) {
+        for (int i = 0; i < cbcs.length; ++i) {
+            if (isLoaded[i]) {
+                ClassBytecodes cbc = cbcs[i];
+                get(cbc.name()).setLoadedBytes(cbc.bytecodes());
+            }
+        }
+    }
+
+    // Map a class name to the current compiled class bytes.
+    void setCurrentBytes(String className, byte[] bytes) {
+        ClassInfo ci = get(className);
+        ci.setCurrentBytes(bytes);
+    }
+
+    // Lookup the ClassInfo by class name, create if it does not exist.
+    ClassInfo get(String className) {
+        return map.computeIfAbsent(className, k -> new ClassInfo(k));
+    }
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Jul 05 22:00:06 2017 +0200
@@ -61,6 +61,14 @@
 import jdk.jshell.TreeDissector.ExpressionInfo;
 import jdk.jshell.Wrap.Range;
 import jdk.jshell.Snippet.Status;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.InternalException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+import jdk.jshell.spi.ExecutionControl.ResolutionException;
+import jdk.jshell.spi.ExecutionControl.RunException;
+import jdk.jshell.spi.ExecutionControl.UserException;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toSet;
 import static java.util.Collections.singletonList;
@@ -541,15 +549,21 @@
         if (si.status().isDefined()) {
             if (si.isExecutable()) {
                 try {
-                value = state.executionControl().invoke(si.classFullName(), DOIT_METHOD_NAME);
+                    value = state.executionControl().invoke(si.classFullName(), DOIT_METHOD_NAME);
                     value = si.subKind().hasValue()
                             ? expunge(value)
                             : "";
-                } catch (EvalException ex) {
+                } catch (ResolutionException ex) {
+                    DeclarationSnippet sn = (DeclarationSnippet) state.maps.getSnippetDeadOrAlive(ex.id());
+                    exception = new UnresolvedReferenceException(sn, ex.getStackTrace());
+                } catch (UserException ex) {
                     exception = translateExecutionException(ex);
-                } catch (JShellException ex) {
-                    // UnresolvedReferenceException
-                    exception = ex;
+                } catch (RunException ex) {
+                    // StopException - no-op
+                } catch (InternalException ex) {
+                    state.debug(ex, "invoke");
+                } catch (EngineTerminationException ex) {
+                    state.closeDown();
                 }
             } else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) {
                 switch (((VarSnippet) si).typeName()) {
@@ -700,15 +714,25 @@
 
     /**
      * If there are classes to load, loads by calling the execution engine.
-     * @param classnames names of the classes to load.
+     * @param classbytecoes names of the classes to load.
      */
-    private void load(Collection<String> classnames) {
-        if (!classnames.isEmpty()) {
-            state.executionControl().load(classnames);
+    private void load(Collection<ClassBytecodes> classbytecoes) {
+        if (!classbytecoes.isEmpty()) {
+            ClassBytecodes[] cbcs = classbytecoes.toArray(new ClassBytecodes[classbytecoes.size()]);
+            try {
+                state.executionControl().load(cbcs);
+                state.classTracker.markLoaded(cbcs);
+            } catch (ClassInstallException ex) {
+                state.classTracker.markLoaded(cbcs, ex.installed());
+            } catch (NotImplementedException ex) {
+                state.debug(ex, "Seriously?!? load not implemented");
+            } catch (EngineTerminationException ex) {
+                state.closeDown();
+            }
         }
     }
 
-    private EvalException translateExecutionException(EvalException ex) {
+    private EvalException translateExecutionException(UserException ex) {
         StackTraceElement[] raw = ex.getStackTrace();
         int last = raw.length;
         do {
@@ -739,7 +763,7 @@
         if (msg.equals("<none>")) {
             msg = null;
         }
-        return new EvalException(msg, ex.getExceptionClassName(), elems);
+        return new EvalException(msg, ex.causeExceptionClass(), elems);
     }
 
     private boolean isWrap(StackTraceElement ste) {
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Wed Jul 05 22:00:06 2017 +0200
@@ -44,13 +44,15 @@
 
 import java.util.function.Supplier;
 import jdk.internal.jshell.debug.InternalDebugControl;
-import jdk.internal.jshell.jdi.FailOverExecutionControl;
+import jdk.jshell.Snippet.Status;
+import jdk.jshell.execution.JDIDefaultExecutionControl;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.ExecutionControlException;
+import jdk.jshell.spi.ExecutionEnv;
+import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
 import static java.util.stream.Collectors.collectingAndThen;
 import static java.util.stream.Collectors.toList;
 import static jdk.jshell.Util.expunge;
-import jdk.jshell.Snippet.Status;
-import jdk.internal.jshell.jdi.JDIExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
 
 /**
  * The JShell evaluation state engine.  This is the central class in the JShell
@@ -90,17 +92,17 @@
     final BiFunction<Snippet, Integer, String> idGenerator;
     final List<String> extraRemoteVMOptions;
     final List<String> extraCompilerOptions;
-    final ExecutionControl executionControl;
+    final ExecutionControl.Generator executionControlGenerator;
 
     private int nextKeyIndex = 1;
 
     final Eval eval;
-    private final Map<String, byte[]> classnameToBytes = new HashMap<>();
+    final ClassTracker classTracker;
     private final Map<Subscription, Consumer<JShell>> shutdownListeners = new HashMap<>();
     private final Map<Subscription, Consumer<SnippetEvent>> keyStatusListeners = new HashMap<>();
     private boolean closed = false;
 
-    private boolean executionControlLaunched = false;
+    private ExecutionControl executionControl = null;
     private SourceCodeAnalysisImpl sourceCodeAnalysis = null;
 
     private static final String L10N_RB_NAME    = "jdk.jshell.resources.l10n";
@@ -114,17 +116,18 @@
         this.idGenerator = b.idGenerator;
         this.extraRemoteVMOptions = b.extraRemoteVMOptions;
         this.extraCompilerOptions = b.extraCompilerOptions;
-        this.executionControl = b.executionControl==null
-                ? new FailOverExecutionControl(
-                        new JDIExecutionControl(),
-                        new JDIExecutionControl(false))
-                : b.executionControl;
+        this.executionControlGenerator = b.executionControlGenerator==null
+                ? failOverExecutionControlGenerator(
+                        JDIDefaultExecutionControl.launch(),
+                        JDIDefaultExecutionControl.listen())
+                : b.executionControlGenerator;
 
         this.maps = new SnippetMaps(this);
         this.keyMap = new KeyMap(this);
         this.outerMap = new OuterWrapMap(this);
         this.taskFactory = new TaskFactory(this);
         this.eval = new Eval(this);
+        this.classTracker = new ClassTracker();
     }
 
     /**
@@ -154,7 +157,7 @@
         BiFunction<Snippet, Integer, String> idGenerator = null;
         List<String> extraRemoteVMOptions = new ArrayList<>();
         List<String> extraCompilerOptions = new ArrayList<>();
-        ExecutionControl executionControl;
+        ExecutionControl.Generator executionControlGenerator;
 
         Builder() { }
 
@@ -310,12 +313,12 @@
          * Sets the custom engine for execution. Snippet execution will be
          * provided by the specified {@link ExecutionControl} instance.
          *
-         * @param execEngine the execution engine
+         * @param executionControlGenerator the execution engine generator
          * @return the {@code Builder} instance (for use in chained
          * initialization)
          */
-        public Builder executionEngine(ExecutionControl execEngine) {
-            this.executionControl = execEngine;
+        public Builder executionEngine(ExecutionControl.Generator executionControlGenerator) {
+            this.executionControlGenerator = executionControlGenerator;
             return this;
         }
 
@@ -397,7 +400,8 @@
      * be an event showing its status changed to OVERWRITTEN, this will not
      * occur for dropped, rejected, or already overwritten declarations.
      * <p>
-     * The execution environment is out of process.  If the evaluated code
+     * If execution environment is out of process, as is the default case, then
+     * if the evaluated code
      * causes the execution environment to terminate, this {@code JShell}
      * instance will be closed but the calling process and VM remain valid.
      * @param input The input String to evaluate
@@ -447,8 +451,14 @@
      * @param path the path to add to the classpath.
      */
     public void addToClasspath(String path) {
-        taskFactory.addToClasspath(path);  // Compiler
-        executionControl().addToClasspath(path);       // Runtime
+        // Compiler
+        taskFactory.addToClasspath(path);
+        // Runtime
+        try {
+            executionControl().addToClasspath(path);
+        } catch (ExecutionControlException ex) {
+            debug(ex, "on addToClasspath(" + path + ")");
+        }
         if (sourceCodeAnalysis != null) {
             sourceCodeAnalysis.classpathChanged();
         }
@@ -468,8 +478,13 @@
      * catching the {@link ThreadDeath} exception.
      */
     public void stop() {
-        if (executionControl != null)
-            executionControl.stop();
+        if (executionControl != null) {
+            try {
+                executionControl.stop();
+            } catch (ExecutionControlException ex) {
+                debug(ex, "on stop()");
+            }
+        }
     }
 
     /**
@@ -622,7 +637,15 @@
             throw new IllegalArgumentException(
                     messageFormat("jshell.exc.var.not.valid",  snippet, snippet.status()));
         }
-        String value = executionControl().varValue(snippet.classFullName(), snippet.name());
+        String value;
+        try {
+            value = executionControl().varValue(snippet.classFullName(), snippet.name());
+        } catch (EngineTerminationException ex) {
+            throw new IllegalStateException(ex.getMessage());
+        } catch (ExecutionControlException ex) {
+            debug(ex, "In varValue()");
+            return "[" + ex.getMessage() + "]";
+        }
         return expunge(value);
     }
 
@@ -696,43 +719,22 @@
         }
 
         @Override
-        public JShell state() {
-            return JShell.this;
-        }
-
-        @Override
         public List<String> extraRemoteVMOptions() {
             return extraRemoteVMOptions;
         }
 
         @Override
-        public byte[] getClassBytes(String classname) {
-            return classnameToBytes.get(classname);
-        }
-
-        @Override
-        public EvalException createEvalException(String message, String exceptionClass, StackTraceElement[] stackElements) {
-            return new EvalException(message, exceptionClass, stackElements);
-        }
-
-        @Override
-        public UnresolvedReferenceException createUnresolvedReferenceException(int id, StackTraceElement[] stackElements) {
-            DeclarationSnippet sn = (DeclarationSnippet) maps.getSnippetDeadOrAlive(id);
-            return new UnresolvedReferenceException(sn, stackElements);
-        }
-
-        @Override
         public void closeDown() {
             JShell.this.closeDown();
         }
+
     }
 
     // --- private / package-private implementation support ---
     ExecutionControl executionControl() {
-        if (!executionControlLaunched) {
+        if (executionControl == null) {
             try {
-                executionControlLaunched = true;
-                executionControl.start(new ExecutionEnvImpl());
+                executionControl =  executionControlGenerator.generate(new ExecutionEnvImpl());
             } catch (Throwable ex) {
                 throw new InternalError("Launching execution engine threw: " + ex.getMessage(), ex);
             }
@@ -740,10 +742,6 @@
         return executionControl;
     }
 
-    void setClassnameToBytes(String classname, byte[] bytes) {
-        classnameToBytes.put(classname, bytes);
-    }
-
     void debug(int flags, String format, Object... args) {
         InternalDebugControl.debug(this, err, flags, format, args);
     }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Wed Jul 05 22:00:06 2017 +0200
@@ -82,7 +82,7 @@
             throw new UnsupportedOperationException("Compiler not available, must be run with full JDK 9.");
         }
         Version current = Version.parse(System.getProperty("java.specification.version"));
-        if (INITIAL_SUPPORTED_VER.compareToIgnoreOpt(current) > 0)  {
+        if (INITIAL_SUPPORTED_VER.compareToIgnoreOptional(current) > 0)  {
             throw new UnsupportedOperationException("Wrong compiler, must be run with full JDK 9.");
         }
         this.fileManager = new MemoryFileManager(
@@ -223,7 +223,6 @@
                     new WrapSourceHandler(),
                     Util.join(new String[] {
                         "-Xshouldstop:at=FLOW", "-Xlint:unchecked",
-                        "-XaddExports:jdk.jshell/jdk.internal.jshell.remote=ALL-UNNAMED",
                         "-proc:none"
                     }, extraArgs));
         }
@@ -267,7 +266,7 @@
 
         CompileTask(final Collection<OuterWrap> wraps) {
             super(wraps.stream(), new WrapSourceHandler(),
-                    "-Xlint:unchecked", "-XaddExports:jdk.jshell/jdk.internal.jshell.remote=ALL-UNNAMED", "-proc:none", "-parameters");
+                    "-Xlint:unchecked", "-proc:none", "-parameters");
         }
 
         boolean compile() {
@@ -286,7 +285,7 @@
             }
             List<String> list = new ArrayList<>();
             for (OutputMemoryJavaFileObject fo : l) {
-                state.setClassnameToBytes(fo.getName(), fo.getBytes());
+                state.classTracker.setCurrentBytes(fo.getName(), fo.getBytes());
                 list.add(fo.getName());
             }
             return list;
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java	Wed Jul 05 22:00:06 2017 +0200
@@ -32,11 +32,16 @@
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Stream;
+import jdk.jshell.ClassTracker.ClassInfo;
 import jdk.jshell.Snippet.Kind;
 import jdk.jshell.Snippet.Status;
 import jdk.jshell.Snippet.SubKind;
 import jdk.jshell.TaskFactory.AnalyzeTask;
 import jdk.jshell.TaskFactory.CompileTask;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toSet;
 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
@@ -75,7 +80,7 @@
     private SnippetEvent replaceOldEvent;
     private List<SnippetEvent> secondaryEvents;
     private boolean isAttemptingCorral;
-    private List<String> toRedefine;
+    private List<ClassInfo> toRedefine;
     private boolean dependenciesNeeded;
 
     Unit(JShell state, Snippet si, Snippet causalSnippet,
@@ -261,30 +266,29 @@
     }
 
     /**
-     * Process the class information from the last compile.
-     * Requires loading of returned list.
+     * Process the class information from the last compile. Requires loading of
+     * returned list.
+     *
      * @return the list of classes to load
      */
-    Stream<String> classesToLoad(List<String> classnames) {
+    Stream<ClassBytecodes> classesToLoad(List<String> classnames) {
         toRedefine = new ArrayList<>();
-        List<String> toLoad = new ArrayList<>();
+        List<ClassBytecodes> toLoad = new ArrayList<>();
         if (status.isDefined() && !isImport()) {
             // Classes should only be loaded/redefined if the compile left them
             // in a defined state.  Imports do not have code and are not loaded.
             for (String cn : classnames) {
-                switch (state.executionControl().getClassStatus(cn)) {
-                    case UNKNOWN:
-                        // If not loaded, add to the list of classes to load.
-                        toLoad.add(cn);
-                        dependenciesNeeded = true;
-                        break;
-                    case NOT_CURRENT:
-                        // If loaded but out of date, add to the list of classes to attempt redefine.
-                        toRedefine.add(cn);
-                        break;
-                    case CURRENT:
-                        // Loaded and current, so nothing to do
-                        break;
+                ClassInfo ci = state.classTracker.get(cn);
+                if (ci.isLoaded()) {
+                    if (ci.isCurrent()) {
+                        // nothing to do
+                    } else {
+                        toRedefine.add(ci);
+                    }
+                } else {
+                    // If not loaded, add to the list of classes to load.
+                    toLoad.add(ci.toClassBytecodes());
+                    dependenciesNeeded = true;
                 }
             }
         }
@@ -292,14 +296,30 @@
     }
 
     /**
-     * Redefine classes needing redefine.
-     * classesToLoad() must be called first.
+     * Redefine classes needing redefine. classesToLoad() must be called first.
+     *
      * @return true if all redefines succeeded (can be vacuously true)
      */
     boolean doRedefines() {
-        return toRedefine.isEmpty()
-                ? true
-                : state.executionControl().redefine(toRedefine);
+        if (toRedefine.isEmpty()) {
+            return true;
+        }
+        ClassBytecodes[] cbcs = toRedefine.stream()
+                .map(ci -> ci.toClassBytecodes())
+                .toArray(size -> new ClassBytecodes[size]);
+        try {
+            state.executionControl().redefine(cbcs);
+            state.classTracker.markLoaded(cbcs);
+            return true;
+        } catch (ClassInstallException ex) {
+            state.classTracker.markLoaded(cbcs, ex.installed());
+            return false;
+        } catch (EngineTerminationException ex) {
+            state.closeDown();
+            return false;
+        } catch (NotImplementedException ex) {
+            return false;
+        }
     }
 
     void markForReplacement() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DefaultLoaderDelegate.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.util.Map;
+import java.util.TreeMap;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.InternalException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+
+/**
+ * The standard implementation of {@link LoaderDelegate} using
+ * a {@link URLClassLoader}.
+ *
+ * @author Robert Field
+ */
+class DefaultLoaderDelegate implements LoaderDelegate {
+
+    private final RemoteClassLoader loader;
+    private final Map<String, Class<?>> klasses = new TreeMap<>();
+
+    class RemoteClassLoader extends URLClassLoader {
+
+        private final Map<String, byte[]> classObjects = new TreeMap<>();
+
+        RemoteClassLoader() {
+            super(new URL[0]);
+        }
+
+        void delare(String name, byte[] bytes) {
+            classObjects.put(name, bytes);
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            byte[] b = classObjects.get(name);
+            if (b == null) {
+                return super.findClass(name);
+            }
+            return super.defineClass(name, b, 0, b.length, (CodeSource) null);
+        }
+
+        @Override
+        public void addURL(URL url) {
+            super.addURL(url);
+        }
+
+    }
+
+    public DefaultLoaderDelegate() {
+        this.loader = new RemoteClassLoader();
+    }
+
+    @Override
+    public void load(ClassBytecodes[] cbcs)
+            throws ClassInstallException, EngineTerminationException {
+        boolean[] loaded = new boolean[cbcs.length];
+        try {
+            for (ClassBytecodes cbc : cbcs) {
+                loader.delare(cbc.name(), cbc.bytecodes());
+            }
+            for (int i = 0; i < cbcs.length; ++i) {
+                ClassBytecodes cbc = cbcs[i];
+                Class<?> klass = loader.loadClass(cbc.name());
+                klasses.put(cbc.name(), klass);
+                loaded[i] = true;
+                // Get class loaded to the point of, at least, preparation
+                klass.getDeclaredMethods();
+            }
+        } catch (Throwable ex) {
+            throw new ClassInstallException("load: " + ex.getMessage(), loaded);
+        }
+    }
+
+
+    @Override
+    public void addToClasspath(String cp)
+            throws EngineTerminationException, InternalException {
+        try {
+            for (String path : cp.split(File.pathSeparator)) {
+                loader.addURL(new File(path).toURI().toURL());
+            }
+        } catch (Exception ex) {
+            throw new InternalException(ex.toString());
+        }
+    }
+
+    @Override
+    public void setClasspath(String path)
+            throws EngineTerminationException, InternalException {
+        throw new NotImplementedException("setClasspath: Not supported yet.");
+    }
+
+    @Override
+    public Class<?> findClass(String name) throws ClassNotFoundException {
+        Class<?> klass = klasses.get(name);
+        if (klass == null) {
+            throw new ClassNotFoundException(name + " not found");
+        } else {
+            return klass;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DemultiplexInput.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+
+/**
+ * Read from an InputStream which has been packetized and write its contents
+ * to the named OutputStreams.
+ *
+ * @author Jan Lahoda
+ * @see Util#demultiplexInput(java.io.InputStream, java.io.OutputStream, java.io.OutputStream, java.io.OutputStream...)
+ */
+class DemultiplexInput extends Thread {
+
+    private final DataInputStream delegate;
+    private final PipeInputStream command;
+    private final Map<String, OutputStream> io;
+
+    DemultiplexInput(InputStream input, PipeInputStream command,
+            Map<String, OutputStream> io) {
+        super("output reader");
+        this.delegate = new DataInputStream(input);
+        this.command = command;
+        this.io = io;
+    }
+
+    @Override
+    public void run() {
+        try {
+            while (true) {
+                int nameLen = delegate.read();
+                if (nameLen == (-1)) {
+                    break;
+                }
+                byte[] name = new byte[nameLen];
+                DemultiplexInput.this.delegate.readFully(name);
+                int dataLen = delegate.read();
+                byte[] data = new byte[dataLen];
+                DemultiplexInput.this.delegate.readFully(data);
+                String chan = new String(name, "UTF-8");
+                if (chan.equals("command")) {
+                    for (byte b : data) {
+                        command.write(Byte.toUnsignedInt(b));
+                    }
+                } else {
+                    OutputStream out = io.get(chan);
+                    if (out == null) {
+                        debug("Unexpected channel name: %s", chan);
+                    } else {
+                        out.write(data);
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            debug(ex, "Failed reading output");
+        } finally {
+            command.close();
+        }
+    }
+
+    /**
+     * Log debugging information. Arguments as for {@code printf}.
+     *
+     * @param format a format string as described in Format string syntax
+     * @param args arguments referenced by the format specifiers in the format
+     * string.
+     */
+    private void debug(String format, Object... args) {
+        // Reserved for future logging
+    }
+
+    /**
+     * Log a serious unexpected internal exception.
+     *
+     * @param ex the exception
+     * @param where a description of the context of the exception
+     */
+    private void debug(Throwable ex, String where) {
+        // Reserved for future logging
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import jdk.jshell.spi.ExecutionControl;
+import jdk.jshell.spi.SPIResolutionException;
+
+/**
+ * An {@link ExecutionControl} implementation that runs in the current process.
+ * May be used directly, or over a channel with
+ * {@link Util#forwardExecutionControl(ExecutionControl, java.io.ObjectInput, java.io.ObjectOutput) }.
+ *
+ * @author Robert Field
+ * @author Jan Lahoda
+ */
+public class DirectExecutionControl implements ExecutionControl {
+
+    private final LoaderDelegate loaderDelegate;
+
+    /**
+     * Creates an instance, delegating loader operations to the specified
+     * delegate.
+     *
+     * @param loaderDelegate the delegate to handle loading classes
+     */
+    public DirectExecutionControl(LoaderDelegate loaderDelegate) {
+        this.loaderDelegate = loaderDelegate;
+    }
+
+    /**
+     * Create an instance using the default class loading.
+     */
+    public DirectExecutionControl() {
+        this(new DefaultLoaderDelegate());
+    }
+
+    @Override
+    public void load(ClassBytecodes[] cbcs)
+            throws ClassInstallException, NotImplementedException, EngineTerminationException {
+        loaderDelegate.load(cbcs);
+    }
+
+    @Override
+    public void redefine(ClassBytecodes[] cbcs)
+            throws ClassInstallException, NotImplementedException, EngineTerminationException {
+        throw new NotImplementedException("redefine not supported");
+    }
+
+    @Override
+    public String invoke(String className, String methodName)
+            throws RunException, InternalException, EngineTerminationException {
+        Method doitMethod;
+        try {
+            Class<?> klass = findClass(className);
+            doitMethod = klass.getDeclaredMethod(methodName, new Class<?>[0]);
+            doitMethod.setAccessible(true);
+        } catch (Throwable ex) {
+            throw new InternalException(ex.toString());
+        }
+
+        try {
+            clientCodeEnter();
+            String result = invoke(doitMethod);
+            System.out.flush();
+            return result;
+        } catch (RunException | InternalException | EngineTerminationException ex) {
+            throw ex;
+        } catch (SPIResolutionException ex) {
+            return throwConvertedInvocationException(ex);
+        } catch (InvocationTargetException ex) {
+            return throwConvertedInvocationException(ex.getCause());
+        } catch (Throwable ex) {
+            return throwConvertedOtherException(ex);
+        } finally {
+            clientCodeLeave();
+        }
+    }
+
+    @Override
+    public String varValue(String className, String varName)
+            throws RunException, EngineTerminationException, InternalException {
+        Object val;
+        try {
+            Class<?> klass = findClass(className);
+            Field var = klass.getDeclaredField(varName);
+            var.setAccessible(true);
+            val = var.get(null);
+        } catch (Throwable ex) {
+            throw new InternalException(ex.toString());
+        }
+
+        try {
+            clientCodeEnter();
+            return valueString(val);
+        } catch (Throwable ex) {
+            return throwConvertedInvocationException(ex);
+        } finally {
+            clientCodeLeave();
+        }
+    }
+
+    @Override
+    public void addToClasspath(String cp)
+            throws EngineTerminationException, InternalException {
+        loaderDelegate.addToClasspath(cp);
+    }
+
+    @Override
+    public void setClasspath(String path)
+            throws EngineTerminationException, InternalException {
+        loaderDelegate.setClasspath(path);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Not supported.
+     */
+    @Override
+    public void stop()
+            throws EngineTerminationException, InternalException {
+        throw new NotImplementedException("stop: Not supported.");
+    }
+
+    @Override
+    public Object extensionCommand(String command, Object arg)
+            throws RunException, EngineTerminationException, InternalException {
+        throw new NotImplementedException("Unknown command: " + command);
+    }
+
+    @Override
+    public void close() {
+    }
+
+    /**
+     * Finds the class with the specified binary name.
+     *
+     * @param name the binary name of the class
+     * @return the Class Object
+     * @throws ClassNotFoundException if the class could not be found
+     */
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        return loaderDelegate.findClass(name);
+    }
+
+    /**
+     * Invoke the specified "doit-method", a static method with no parameters.
+     * The {@link DirectExecutionControl#invoke(java.lang.String, java.lang.String) }
+     * in this class will call this to invoke.
+     *
+     * @param doitMethod the Method to invoke
+     * @return the value or null
+     * @throws Exception any exceptions thrown by
+     * {@link java.lang.reflect.Method#invoke(Object, Object...) }
+     * or any {@link ExecutionControl.ExecutionControlException}
+     * to pass-through.
+     */
+    protected String invoke(Method doitMethod) throws Exception {
+        Object res = doitMethod.invoke(null, new Object[0]);
+        return valueString(res);
+    }
+
+    /**
+     * Converts the {@code Object} value from
+     * {@link ExecutionControl#invoke(String, String)  } or
+     * {@link ExecutionControl#varValue(String, String)   } to {@code String}.
+     *
+     * @param value the value to convert
+     * @return the {@code String} representation
+     */
+    protected static String valueString(Object value) {
+        if (value == null) {
+            return "null";
+        } else if (value instanceof String) {
+            return "\"" + (String) value + "\"";
+        } else if (value instanceof Character) {
+            return "'" + value + "'";
+        } else {
+            return value.toString();
+        }
+    }
+
+    /**
+     * Converts incoming exceptions in user code into instances of subtypes of
+     * {@link ExecutionControl.ExecutionControlException} and throws the
+     * converted exception.
+     *
+     * @param cause the exception to convert
+     * @return never returns as it always throws
+     * @throws ExecutionControl.RunException for normal exception occurrences
+     * @throws ExecutionControl.InternalException for internal problems
+     */
+    protected String throwConvertedInvocationException(Throwable cause) throws RunException, InternalException {
+        if (cause instanceof SPIResolutionException) {
+            SPIResolutionException spire = (SPIResolutionException) cause;
+            throw new ResolutionException(spire.id(), spire.getStackTrace());
+        } else {
+            throw new UserException(cause.getMessage(), cause.getClass().getName(), cause.getStackTrace());
+        }
+    }
+
+    /**
+     * Converts incoming exceptions in agent code into instances of subtypes of
+     * {@link ExecutionControl.ExecutionControlException} and throws the
+     * converted exception.
+     *
+     * @param ex the exception to convert
+     * @return never returns as it always throws
+     * @throws ExecutionControl.RunException for normal exception occurrences
+     * @throws ExecutionControl.InternalException for internal problems
+     */
+    protected String throwConvertedOtherException(Throwable ex) throws RunException, InternalException {
+        throw new InternalException(ex.toString());
+    }
+
+    /**
+     * Marks entry into user code.
+     *
+     * @throws ExecutionControl.InternalException in unexpected failure cases
+     */
+    protected void clientCodeEnter() throws InternalException {
+    }
+
+    /**
+     * Marks departure from user code.
+     *
+     * @throws ExecutionControl.InternalException in unexpected failure cases
+     */
+    protected void clientCodeLeave() throws InternalException {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/ExecutionControlForwarder.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import jdk.jshell.spi.ExecutionControl;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.InternalException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+import jdk.jshell.spi.ExecutionControl.ResolutionException;
+import jdk.jshell.spi.ExecutionControl.StoppedException;
+import jdk.jshell.spi.ExecutionControl.UserException;
+import static jdk.jshell.execution.RemoteCodes.*;
+
+/**
+ * Forwards commands from the input to the specified {@link ExecutionControl}
+ * instance, then responses back on the output.
+ */
+class ExecutionControlForwarder {
+
+    private final ExecutionControl ec;
+    private final ObjectInput in;
+    private final ObjectOutput out;
+
+    ExecutionControlForwarder(ExecutionControl ec, ObjectInput in, ObjectOutput out) {
+        this.ec = ec;
+        this.in = in;
+        this.out = out;
+    }
+
+    private boolean writeSuccess() throws IOException {
+        writeStatus(RESULT_SUCCESS);
+        flush();
+        return true;
+    }
+
+    private boolean writeSuccessAndResult(String result) throws IOException {
+        writeStatus(RESULT_SUCCESS);
+        writeUTF(result);
+        flush();
+        return true;
+    }
+
+    private boolean writeSuccessAndResult(Object result) throws IOException {
+        writeStatus(RESULT_SUCCESS);
+        writeObject(result);
+        flush();
+        return true;
+    }
+
+    private void writeStatus(int status) throws IOException {
+        out.writeInt(status);
+    }
+
+    private void writeObject(Object o) throws IOException {
+        out.writeObject(o);
+    }
+
+    private void writeInt(int i) throws IOException {
+        out.writeInt(i);
+    }
+
+    private void writeUTF(String s) throws IOException {
+        if (s == null) {
+            s = "";
+        }
+        out.writeUTF(s);
+    }
+
+    private void flush() throws IOException {
+        out.flush();
+    }
+
+    private boolean processCommand() throws IOException {
+        try {
+            int prefix = in.readInt();
+            if (prefix != COMMAND_PREFIX) {
+                throw new EngineTerminationException("Invalid command prefix: " + prefix);
+            }
+            String cmd = in.readUTF();
+            switch (cmd) {
+                case CMD_LOAD: {
+                    // Load a generated class file over the wire
+                    ClassBytecodes[] cbcs = (ClassBytecodes[]) in.readObject();
+                    ec.load(cbcs);
+                    return writeSuccess();
+                }
+                case CMD_REDEFINE: {
+                    // Load a generated class file over the wire
+                    ClassBytecodes[] cbcs = (ClassBytecodes[]) in.readObject();
+                    ec.redefine(cbcs);
+                    return writeSuccess();
+                }
+                case CMD_INVOKE: {
+                    // Invoke executable entry point in loaded code
+                    String className = in.readUTF();
+                    String methodName = in.readUTF();
+                    String res = ec.invoke(className, methodName);
+                    return writeSuccessAndResult(res);
+                }
+                case CMD_VAR_VALUE: {
+                    // Retrieve a variable value
+                    String className = in.readUTF();
+                    String varName = in.readUTF();
+                    String res = ec.varValue(className, varName);
+                    return writeSuccessAndResult(res);
+                }
+                case CMD_ADD_CLASSPATH: {
+                    // Append to the claspath
+                    String cp = in.readUTF();
+                    ec.addToClasspath(cp);
+                    return writeSuccess();
+                }
+                case CMD_SET_CLASSPATH: {
+                    // Set the claspath
+                    String cp = in.readUTF();
+                    ec.setClasspath(cp);
+                    return writeSuccess();
+                }
+                case CMD_STOP: {
+                    // Stop the current execution
+                    try {
+                        ec.stop();
+                    } catch (Throwable ex) {
+                        // JShell-core not waiting for a result, ignore
+                    }
+                    return true;
+                }
+                case CMD_CLOSE: {
+                    // Terminate this process
+                    try {
+                        ec.close();
+                    } catch (Throwable ex) {
+                        // JShell-core not waiting for a result, ignore
+                    }
+                    return true;
+                }
+                default: {
+                    Object arg = in.readObject();
+                    Object res = ec.extensionCommand(cmd, arg);
+                    return writeSuccessAndResult(res);
+                }
+            }
+        } catch (IOException ex) {
+            // handled by the outer level
+            throw ex;
+        } catch (EngineTerminationException ex) {
+            writeStatus(RESULT_TERMINATED);
+            writeUTF(ex.getMessage());
+            flush();
+            return false;
+        } catch (NotImplementedException ex) {
+            writeStatus(RESULT_NOT_IMPLEMENTED);
+            writeUTF(ex.getMessage());
+            flush();
+            return true;
+        } catch (InternalException ex) {
+            writeStatus(RESULT_INTERNAL_PROBLEM);
+            writeUTF(ex.getMessage());
+            flush();
+            return true;
+        } catch (ClassInstallException ex) {
+            writeStatus(RESULT_CLASS_INSTALL_EXCEPTION);
+            writeUTF(ex.getMessage());
+            writeObject(ex.installed());
+            flush();
+            return true;
+        } catch (UserException ex) {
+            writeStatus(RESULT_USER_EXCEPTION);
+            writeUTF(ex.getMessage());
+            writeUTF(ex.causeExceptionClass());
+            writeObject(ex.getStackTrace());
+            flush();
+            return true;
+        } catch (ResolutionException ex) {
+            writeStatus(RESULT_CORRALLED);
+            writeInt(ex.id());
+            writeObject(ex.getStackTrace());
+            flush();
+            return true;
+        } catch (StoppedException ex) {
+            writeStatus(RESULT_STOPPED);
+            flush();
+            return true;
+        } catch (Throwable ex) {
+            writeStatus(RESULT_TERMINATED);
+            writeUTF(ex.getMessage());
+            flush();
+            return false;
+        }
+    }
+
+    void commandLoop() {
+        try {
+            while (processCommand()) {
+                // condition is loop action
+            }
+        } catch (IOException ex) {
+            // drop out of loop
+        }
+    }
+
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Internal.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.jshell.execution;
-
-/**
- * Temp class needed so the package exists.
- */
-class Internal {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import com.sun.jdi.BooleanValue;
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.Field;
+import com.sun.jdi.IncompatibleThreadStateException;
+import com.sun.jdi.InvalidTypeException;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.StackFrame;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VirtualMachine;
+import jdk.jshell.spi.ExecutionControl;
+import jdk.jshell.spi.ExecutionEnv;
+import static jdk.jshell.execution.Util.remoteInput;
+
+/**
+ * The implementation of {@link jdk.jshell.spi.ExecutionControl} that the
+ * JShell-core uses by default.
+ * Launches a remote process -- the "remote agent".
+ * Interfaces to the remote agent over a socket and via JDI.
+ * Designed to work with {@link RemoteExecutionControl}.
+ *
+ * @author Robert Field
+ * @author Jan Lahoda
+ */
+public class JDIDefaultExecutionControl extends JDIExecutionControl {
+
+    private static final String REMOTE_AGENT = RemoteExecutionControl.class.getName();
+
+    private VirtualMachine vm;
+    private Process process;
+
+    private final Object STOP_LOCK = new Object();
+    private boolean userCodeRunning = false;
+
+    /**
+     * Creates an ExecutionControl instance based on a JDI
+     * {@code LaunchingConnector}.
+     *
+     * @return the generator
+     */
+    public static ExecutionControl.Generator launch() {
+        return env -> create(env, true);
+    }
+
+    /**
+     * Creates an ExecutionControl instance based on a JDI
+     * {@code ListeningConnector}.
+     *
+     * @return the generator
+     */
+    public static ExecutionControl.Generator listen() {
+        return env -> create(env, false);
+    }
+
+    /**
+     * Creates an ExecutionControl instance based on a JDI
+     * {@code ListeningConnector} or {@code LaunchingConnector}.
+     *
+     * Initialize JDI and use it to launch the remote JVM. Set-up a socket for
+     * commands and results. This socket also transports the user
+     * input/output/error.
+     *
+     * @param env the context passed by
+     * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }
+     * @return the channel
+     * @throws IOException if there are errors in set-up
+     */
+    private static JDIDefaultExecutionControl create(ExecutionEnv env, boolean isLaunch) throws IOException {
+        try (final ServerSocket listener = new ServerSocket(0)) {
+            // timeout after 60 seconds
+            listener.setSoTimeout(60000);
+            int port = listener.getLocalPort();
+
+            // Set-up the JDI connection
+            JDIInitiator jdii = new JDIInitiator(port,
+                    env.extraRemoteVMOptions(), REMOTE_AGENT, isLaunch);
+            VirtualMachine vm = jdii.vm();
+            Process process = jdii.process();
+
+            // Forward input to the remote agent
+            Util.forwardInputToRemote(env.userIn(), process.getOutputStream(),
+                    ex -> debug(ex, "input forwarding failure"));
+
+            List<Consumer<String>> deathListeners = new ArrayList<>();
+            deathListeners.add(s -> env.closeDown());
+            Util.detectJDIExitEvent(vm, s -> {
+                for (Consumer<String> h : deathListeners) {
+                    h.accept(s);
+                }
+            });
+
+            // Set-up the commands/reslts on the socket.  Piggy-back snippet
+            // output.
+            Socket socket = listener.accept();
+            // out before in -- match remote creation so we don't hang
+            ObjectOutput cmdout = new ObjectOutputStream(socket.getOutputStream());
+            Map<String, OutputStream> io = new HashMap<>();
+            io.put("out", env.userOut());
+            io.put("err", env.userErr());
+            ObjectInput cmdin = remoteInput(socket.getInputStream(), io);
+            return new JDIDefaultExecutionControl(cmdout, cmdin, vm, process, deathListeners);
+        }
+    }
+
+    /**
+     * Create an instance.
+     *
+     * @param cmdout the output for commands
+     * @param cmdin the input for responses
+     */
+    private JDIDefaultExecutionControl(ObjectOutput cmdout, ObjectInput cmdin,
+            VirtualMachine vm, Process process, List<Consumer<String>> deathListeners) {
+        super(cmdout, cmdin);
+        this.vm = vm;
+        this.process = process;
+        deathListeners.add(s -> disposeVM());
+    }
+
+    @Override
+    public String invoke(String classname, String methodname)
+            throws RunException,
+            EngineTerminationException, InternalException {
+        String res;
+        synchronized (STOP_LOCK) {
+            userCodeRunning = true;
+        }
+        try {
+            res = super.invoke(classname, methodname);
+        } finally {
+            synchronized (STOP_LOCK) {
+                userCodeRunning = false;
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Interrupts a running remote invoke by manipulating remote variables
+     * and sending a stop via JDI.
+     *
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws InternalException an internal problem occurred
+     */
+    @Override
+    public void stop() throws EngineTerminationException, InternalException {
+        synchronized (STOP_LOCK) {
+            if (!userCodeRunning) {
+                return;
+            }
+
+            vm().suspend();
+            try {
+                OUTER:
+                for (ThreadReference thread : vm().allThreads()) {
+                    // could also tag the thread (e.g. using name), to find it easier
+                    for (StackFrame frame : thread.frames()) {
+                        if (REMOTE_AGENT.equals(frame.location().declaringType().name()) &&
+                                (    "invoke".equals(frame.location().method().name())
+                                || "varValue".equals(frame.location().method().name()))) {
+                            ObjectReference thiz = frame.thisObject();
+                            Field inClientCode = thiz.referenceType().fieldByName("inClientCode");
+                            Field expectingStop = thiz.referenceType().fieldByName("expectingStop");
+                            Field stopException = thiz.referenceType().fieldByName("stopException");
+                            if (((BooleanValue) thiz.getValue(inClientCode)).value()) {
+                                thiz.setValue(expectingStop, vm().mirrorOf(true));
+                                ObjectReference stopInstance = (ObjectReference) thiz.getValue(stopException);
+
+                                vm().resume();
+                                debug("Attempting to stop the client code...\n");
+                                thread.stop(stopInstance);
+                                thiz.setValue(expectingStop, vm().mirrorOf(false));
+                            }
+
+                            break OUTER;
+                        }
+                    }
+                }
+            } catch (ClassNotLoadedException | IncompatibleThreadStateException | InvalidTypeException ex) {
+                throw new InternalException("Exception on remote stop: " + ex);
+            } finally {
+                vm().resume();
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        disposeVM();
+    }
+
+    private synchronized void disposeVM() {
+        try {
+            if (vm != null) {
+                vm.dispose(); // This could NPE, so it is caught below
+                vm = null;
+            }
+        } catch (VMDisconnectedException ex) {
+            // Ignore if already closed
+        } catch (Throwable ex) {
+            debug(ex, "disposeVM");
+        } finally {
+            if (process != null) {
+                process.destroy();
+                process = null;
+            }
+        }
+    }
+
+    @Override
+    protected synchronized VirtualMachine vm() throws EngineTerminationException {
+        if (vm == null) {
+            throw new EngineTerminationException("VM closed");
+        } else {
+            return vm;
+        }
+    }
+
+    /**
+     * Log debugging information. Arguments as for {@code printf}.
+     *
+     * @param format a format string as described in Format string syntax
+     * @param args arguments referenced by the format specifiers in the format
+     * string.
+     */
+    private static void debug(String format, Object... args) {
+        // Reserved for future logging
+    }
+
+    /**
+     * Log a serious unexpected internal exception.
+     *
+     * @param ex the exception
+     * @param where a description of the context of the exception
+     */
+    private static void debug(Throwable ex, String where) {
+        // Reserved for future logging
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIEventHandler.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jshell.execution;
+
+import java.util.function.Consumer;
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+
+/**
+ * Handler of Java Debug Interface events.
+ * Adapted from jdb EventHandler.
+ * Only exit and disconnect events processed.
+ */
+class JDIEventHandler implements Runnable {
+
+    private final Thread thread;
+    private volatile boolean connected = true;
+    private boolean completed = false;
+    private final VirtualMachine vm;
+    private final Consumer<String> reportVMExit;
+
+    /**
+     * Creates an event handler. Start with {@code start()}.
+     *
+     * @param vm the virtual machine for which to handle events
+     * @param reportVMExit callback to report exit/disconnect
+     * (passed true if the VM has died)
+     */
+    JDIEventHandler(VirtualMachine vm, Consumer<String> reportVMExit) {
+        this.vm = vm;
+        this.reportVMExit = reportVMExit;
+        this.thread = new Thread(this, "event-handler");
+    }
+
+    /**
+     * Starts the event handler.
+     */
+    void start() {
+        thread.start();
+    }
+
+    synchronized void shutdown() {
+        connected = false;  // force run() loop termination
+        thread.interrupt();
+        while (!completed) {
+            try {wait();} catch (InterruptedException exc) {}
+        }
+    }
+
+    @Override
+    public void run() {
+        EventQueue queue = vm.eventQueue();
+        while (connected) {
+            try {
+                EventSet eventSet = queue.remove();
+                boolean resumeStoppedApp = false;
+                EventIterator it = eventSet.eventIterator();
+                while (it.hasNext()) {
+                    resumeStoppedApp |= handleEvent(it.nextEvent());
+                }
+
+                if (resumeStoppedApp) {
+                    eventSet.resume();
+                }
+            } catch (InterruptedException exc) {
+                // Do nothing. Any changes will be seen at top of loop.
+            } catch (VMDisconnectedException discExc) {
+                handleDisconnectedException();
+                break;
+            }
+        }
+        synchronized (this) {
+            completed = true;
+            notifyAll();
+        }
+    }
+
+    private boolean handleEvent(Event event) {
+        handleExitEvent(event);
+        return true;
+    }
+
+    private void handleExitEvent(Event event) {
+        if (event instanceof VMDeathEvent) {
+            reportVMExit.accept("VM Died");
+        } else if (event instanceof VMDisconnectEvent) {
+            connected = false;
+            reportVMExit.accept("VM Disconnected");
+        } else {
+            // ignore everything else
+        }
+    }
+
+    private synchronized void handleDisconnectedException() {
+        /*
+         * A VMDisconnectedException has happened while dealing with
+         * another event. We need to flush the event queue, dealing only
+         * with exit events (VMDeath, VMDisconnect) so that we terminate
+         * correctly.
+         */
+        EventQueue queue = vm.eventQueue();
+        while (connected) {
+            try {
+                EventSet eventSet = queue.remove();
+                EventIterator iter = eventSet.eventIterator();
+                while (iter.hasNext()) {
+                    handleExitEvent(iter.next());
+                }
+            } catch (InterruptedException exc) {
+                // ignore
+            } catch (InternalError exc) {
+                // ignore
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIExecutionControl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jshell.execution;
+
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.VirtualMachine;
+import jdk.jshell.spi.ExecutionControl;
+import static java.util.stream.Collectors.toMap;
+
+/**
+ * Abstract JDI implementation of {@link jdk.jshell.spi.ExecutionControl}
+ */
+public abstract class JDIExecutionControl extends StreamingExecutionControl implements ExecutionControl {
+
+    /**
+     * Mapping from class names to JDI {@link ReferenceType}.
+     */
+    private final Map<String, ReferenceType> toReferenceType = new HashMap<>();
+
+    /**
+     * Create an instance.
+     * @param out the output from the remote agent
+     * @param in the input to the remote agent
+     */
+    protected JDIExecutionControl(ObjectOutput out, ObjectInput in) {
+        super(out, in);
+    }
+
+    /**
+     * Returns the JDI {@link VirtualMachine} instance.
+     *
+     * @return the virtual machine
+     * @throws EngineTerminationException if the VM is dead/disconnected
+     */
+    protected abstract VirtualMachine vm() throws EngineTerminationException;
+
+    /**
+     * Redefine the specified classes. Where 'redefine' is, as in JDI and JVMTI,
+     * an in-place replacement of the classes (preserving class identity) --
+     * that is, existing references to the class do not need to be recompiled.
+     * This implementation uses JDI
+     * {@link com.sun.jdi.VirtualMachine#redefineClasses(java.util.Map) }.
+     * It will be unsuccessful if
+     * the signature of the class has changed (see the JDI spec). The
+     * JShell-core is designed to adapt to unsuccessful redefine.
+     */
+    @Override
+    public void redefine(ClassBytecodes[] cbcs)
+            throws ClassInstallException, EngineTerminationException {
+        try {
+            // Convert to the JDI ReferenceType to class bytes map form needed
+            // by JDI.
+            VirtualMachine vm = vm();
+            Map<ReferenceType, byte[]> rmp = Stream.of(cbcs)
+                    .collect(toMap(
+                            cbc -> referenceType(vm, cbc.name()),
+                            cbc -> cbc.bytecodes()));
+            // Attempt redefine.  Throws exceptions on failure.
+            vm().redefineClasses(rmp);
+        } catch (EngineTerminationException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            throw new ClassInstallException("redefine: " + ex.getMessage(), new boolean[cbcs.length]);
+        }
+    }
+
+    /**
+     * Returns the JDI {@link ReferenceType} corresponding to the specified
+     * class name.
+     *
+     * @param vm the current JDI {@link VirtualMachine} as returned by
+     * {@code vm()}
+     * @param name the class name to look-up
+     * @return the corresponding {@link ReferenceType}
+     */
+    protected ReferenceType referenceType(VirtualMachine vm, String name) {
+        return toReferenceType.computeIfAbsent(name, n -> nameToRef(vm, n));
+    }
+
+    private static ReferenceType nameToRef(VirtualMachine vm, String name) {
+        List<ReferenceType> rtl = vm.classesByName(name);
+        if (rtl.size() != 1) {
+            return null;
+        }
+        return rtl.get(0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIInitiator.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import com.sun.jdi.Bootstrap;
+import com.sun.jdi.VirtualMachine;
+import com.sun.jdi.connect.Connector;
+import com.sun.jdi.connect.LaunchingConnector;
+import com.sun.jdi.connect.ListeningConnector;
+
+/**
+ * Sets up a JDI connection, providing the resulting JDI {@link VirtualMachine}
+ * and the {@link Process} the remote agent is running in.
+ */
+public class JDIInitiator {
+
+    private VirtualMachine vm;
+    private Process process = null;
+    private final Connector connector;
+    private final String remoteAgent;
+    private final Map<String, com.sun.jdi.connect.Connector.Argument> connectorArgs;
+
+    /**
+     * Start the remote agent and establish a JDI connection to it.
+     *
+     * @param port the socket port for (non-JDI) commands
+     * @param remoteVMOptions any user requested VM options
+     * @param remoteAgent full class name of remote agent to launch
+     * @param isLaunch does JDI do the launch? That is, LaunchingConnector,
+     * otherwise we start explicitly and use ListeningConnector
+     */
+    public JDIInitiator(int port, List<String> remoteVMOptions,
+            String remoteAgent, boolean isLaunch) {
+        this.remoteAgent = remoteAgent;
+        String connectorName
+                = isLaunch
+                        ? "com.sun.jdi.CommandLineLaunch"
+                        : "com.sun.jdi.SocketListen";
+        this.connector = findConnector(connectorName);
+        if (connector == null) {
+            throw new IllegalArgumentException("No connector named: " + connectorName);
+        }
+        Map<String, String> argumentName2Value
+                = isLaunch
+                        ? launchArgs(port, String.join(" ", remoteVMOptions))
+                        : new HashMap<>();
+        this.connectorArgs = mergeConnectorArgs(connector, argumentName2Value);
+        this.vm = isLaunch
+                ? launchTarget()
+                : listenTarget(port, remoteVMOptions);
+
+    }
+
+    /**
+     * Returns the resulting {@code VirtualMachine} instance.
+     *
+     * @return the virtual machine
+     */
+    public VirtualMachine vm() {
+        return vm;
+    }
+
+    /**
+     * Returns the launched process.
+     *
+     * @return the remote agent process
+     */
+    public Process process() {
+        return process;
+    }
+
+    /* launch child target vm */
+    private VirtualMachine launchTarget() {
+        LaunchingConnector launcher = (LaunchingConnector) connector;
+        try {
+            VirtualMachine new_vm = launcher.launch(connectorArgs);
+            process = new_vm.process();
+            return new_vm;
+        } catch (Exception ex) {
+            reportLaunchFail(ex, "launch");
+        }
+        return null;
+    }
+
+    /**
+     * Directly launch the remote agent and connect JDI to it with a
+     * ListeningConnector.
+     */
+    private VirtualMachine listenTarget(int port, List<String> remoteVMOptions) {
+        ListeningConnector listener = (ListeningConnector) connector;
+        try {
+            // Start listening, get the JDI connection address
+            String addr = listener.startListening(connectorArgs);
+            debug("Listening at address: " + addr);
+
+            // Launch the RemoteAgent requesting a connection on that address
+            String javaHome = System.getProperty("java.home");
+            List<String> args = new ArrayList<>();
+            args.add(javaHome == null
+                    ? "java"
+                    : javaHome + File.separator + "bin" + File.separator + "java");
+            args.add("-agentlib:jdwp=transport=" + connector.transport().name() +
+                    ",address=" + addr);
+            args.addAll(remoteVMOptions);
+            args.add(remoteAgent);
+            args.add("" + port);
+            ProcessBuilder pb = new ProcessBuilder(args);
+            process = pb.start();
+
+            // Forward out, err, and in
+            // Accept the connection from the remote agent
+            vm = listener.accept(connectorArgs);
+            listener.stopListening(connectorArgs);
+            return vm;
+        } catch (Exception ex) {
+            reportLaunchFail(ex, "listen");
+        }
+        return null;
+    }
+
+    private Connector findConnector(String name) {
+        for (Connector cntor
+                : Bootstrap.virtualMachineManager().allConnectors()) {
+            if (cntor.name().equals(name)) {
+                return cntor;
+            }
+        }
+        return null;
+    }
+
+    private Map<String, Connector.Argument> mergeConnectorArgs(Connector connector, Map<String, String> argumentName2Value) {
+        Map<String, Connector.Argument> arguments = connector.defaultArguments();
+
+        for (Entry<String, String> argumentEntry : argumentName2Value.entrySet()) {
+            String name = argumentEntry.getKey();
+            String value = argumentEntry.getValue();
+            Connector.Argument argument = arguments.get(name);
+
+            if (argument == null) {
+                throw new IllegalArgumentException("Argument is not defined for connector:" +
+                        name + " -- " + connector.name());
+            }
+
+            argument.setValue(value);
+        }
+
+        return arguments;
+    }
+
+    /**
+     * The JShell specific Connector args for the LaunchingConnector.
+     *
+     * @param portthe socket port for (non-JDI) commands
+     * @param remoteVMOptions any user requested VM options
+     * @return the argument map
+     */
+    private Map<String, String> launchArgs(int port, String remoteVMOptions) {
+        Map<String, String> argumentName2Value = new HashMap<>();
+        argumentName2Value.put("main", remoteAgent + " " + port);
+        argumentName2Value.put("options", remoteVMOptions);
+        return argumentName2Value;
+    }
+
+    private void reportLaunchFail(Exception ex, String context) {
+        throw new InternalError("Failed remote " + context + ": " + connector +
+                " -- " + connectorArgs, ex);
+    }
+
+    /**
+     * Log debugging information. Arguments as for {@code printf}.
+     *
+     * @param format a format string as described in Format string syntax
+     * @param args arguments referenced by the format specifiers in the format
+     * string.
+     */
+    private void debug(String format, Object... args) {
+        // Reserved for future logging
+    }
+
+    /**
+     * Log a serious unexpected internal exception.
+     *
+     * @param ex the exception
+     * @param where a description of the context of the exception
+     */
+    private void debug(Throwable ex, String where) {
+        // Reserved for future logging
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/LoaderDelegate.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.InternalException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+
+/**
+ * This interface specifies the loading specific subset of
+ * {@link jdk.jshell.spi.ExecutionControl}.  For use in encapsulating the
+ * {@link java.lang.ClassLoader} implementation.
+ */
+public interface LoaderDelegate {
+
+    /**
+     * Attempts to load new classes.
+     *
+     * @param cbcs the class name and bytecodes to load
+     * @throws ClassInstallException exception occurred loading the classes,
+     * some or all were not loaded
+     * @throws NotImplementedException if not implemented
+     * @throws EngineTerminationException the execution engine has terminated
+     */
+    void load(ClassBytecodes[] cbcs)
+            throws ClassInstallException, NotImplementedException, EngineTerminationException;
+
+    /**
+     * Adds the path to the execution class path.
+     *
+     * @param path the path to add
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws InternalException an internal problem occurred
+     */
+    void addToClasspath(String path)
+            throws EngineTerminationException, InternalException;
+
+    /**
+     * Sets the execution class path to the specified path.
+     *
+     * @param path the path to add
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws InternalException an internal problem occurred
+     */
+    void setClasspath(String path)
+            throws EngineTerminationException, InternalException;
+
+    /**
+     * Finds the class with the specified binary name.
+     *
+     * @param name the binary name of the class
+     * @return the Class Object
+     * @throws ClassNotFoundException if the class could not be found
+     */
+    Class<?> findClass(String name) throws ClassNotFoundException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicReference;
+import jdk.jshell.spi.ExecutionControl;
+
+/**
+ * An implementation of {@link jdk.jshell.spi.ExecutionControl} which executes
+ * in the same JVM as the JShell-core.
+ *
+ * @author Grigory Ptashko
+ */
+public class LocalExecutionControl extends DirectExecutionControl {
+
+    private final Object STOP_LOCK = new Object();
+    private boolean userCodeRunning = false;
+    private ThreadGroup execThreadGroup;
+
+    /**
+     * Creates a local ExecutionControl instance.
+     *
+     * @return the generator
+     */
+    public static ExecutionControl.Generator create() {
+        return env -> new LocalExecutionControl();
+    }
+
+    /**
+     * Creates an instance, delegating loader operations to the specified
+     * delegate.
+     *
+     * @param loaderDelegate the delegate to handle loading classes
+     */
+    public LocalExecutionControl(LoaderDelegate loaderDelegate) {
+        super(loaderDelegate);
+    }
+
+    /**
+     * Create an instance using the default class loading.
+     */
+    public LocalExecutionControl() {
+    }
+
+    @Override
+    protected String invoke(Method doitMethod) throws Exception {
+        execThreadGroup = new ThreadGroup("JShell process local execution");
+
+        AtomicReference<InvocationTargetException> iteEx = new AtomicReference<>();
+        AtomicReference<IllegalAccessException> iaeEx = new AtomicReference<>();
+        AtomicReference<NoSuchMethodException> nmeEx = new AtomicReference<>();
+        AtomicReference<Boolean> stopped = new AtomicReference<>(false);
+
+        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
+            if (e instanceof InvocationTargetException) {
+                if (e.getCause() instanceof ThreadDeath) {
+                    stopped.set(true);
+                } else {
+                    iteEx.set((InvocationTargetException) e);
+                }
+            } else if (e instanceof IllegalAccessException) {
+                iaeEx.set((IllegalAccessException) e);
+            } else if (e instanceof NoSuchMethodException) {
+                nmeEx.set((NoSuchMethodException) e);
+            } else if (e instanceof ThreadDeath) {
+                stopped.set(true);
+            }
+        });
+
+        final Object[] res = new Object[1];
+        Thread snippetThread = new Thread(execThreadGroup, () -> {
+            try {
+                res[0] = doitMethod.invoke(null, new Object[0]);
+            } catch (InvocationTargetException e) {
+                if (e.getCause() instanceof ThreadDeath) {
+                    stopped.set(true);
+                } else {
+                    iteEx.set(e);
+                }
+            } catch (IllegalAccessException e) {
+                iaeEx.set(e);
+            } catch (ThreadDeath e) {
+                stopped.set(true);
+            }
+        });
+
+        snippetThread.start();
+        Thread[] threadList = new Thread[execThreadGroup.activeCount()];
+        execThreadGroup.enumerate(threadList);
+        for (Thread thread : threadList) {
+            if (thread != null) {
+                thread.join();
+            }
+        }
+
+        if (stopped.get()) {
+            throw new StoppedException();
+        }
+
+        if (iteEx.get() != null) {
+            throw iteEx.get();
+        } else if (nmeEx.get() != null) {
+            throw nmeEx.get();
+        } else if (iaeEx.get() != null) {
+            throw iaeEx.get();
+        }
+
+        return valueString(res[0]);
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public void stop() throws EngineTerminationException, InternalException {
+        synchronized (STOP_LOCK) {
+            if (!userCodeRunning) {
+                return;
+            }
+            if (execThreadGroup == null) {
+                throw new InternalException("Process-local code snippets thread group is null. Aborting stop.");
+            }
+
+            execThreadGroup.stop();
+        }
+    }
+
+    @Override
+    protected void clientCodeEnter() {
+        synchronized (STOP_LOCK) {
+            userCodeRunning = true;
+        }
+    }
+
+    @Override
+    protected void clientCodeLeave() {
+        synchronized (STOP_LOCK) {
+            userCodeRunning = false;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/MultiplexingOutputStream.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Packetize an OutputStream, dividing it into named channels.
+ *
+ * @author Jan Lahoda
+ */
+class MultiplexingOutputStream extends OutputStream {
+
+    private static final int PACKET_SIZE = 127;
+    private final byte[] name;
+    private final OutputStream delegate;
+
+    MultiplexingOutputStream(String name, OutputStream delegate) {
+        try {
+            this.name = name.getBytes("UTF-8");
+            this.delegate = delegate;
+        } catch (UnsupportedEncodingException ex) {
+            throw new IllegalStateException(ex); //should not happen
+        }
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        synchronized (delegate) {
+            delegate.write(name.length); //assuming the len is small enough to fit into byte
+            delegate.write(name);
+            delegate.write(1);
+            delegate.write(b);
+            delegate.flush();
+        }
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        synchronized (delegate) {
+            int i = 0;
+            while (len > 0) {
+                int size = Math.min(PACKET_SIZE, len);
+                delegate.write(name.length); //assuming the len is small enough to fit into byte
+                delegate.write(name);
+                delegate.write(size);
+                delegate.write(b, off + i, size);
+                i += size;
+                len -= size;
+            }
+            delegate.flush();
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        super.flush();
+        delegate.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        super.close();
+        delegate.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/PipeInputStream.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.InputStream;
+
+/**
+ *
+ * @author Jan Lahoda
+ */
+class PipeInputStream extends InputStream {
+
+    private static final int INITIAL_SIZE = 128;
+    private int[] buffer = new int[INITIAL_SIZE];
+    private int start;
+    private int end;
+    private boolean closed;
+
+    @Override
+    public synchronized int read() {
+        while (start == end) {
+            if (closed) {
+                return -1;
+            }
+            try {
+                wait();
+            } catch (InterruptedException ex) {
+                //ignore
+            }
+        }
+        try {
+            return buffer[start];
+        } finally {
+            start = (start + 1) % buffer.length;
+        }
+    }
+
+    public synchronized void write(int b) {
+        if (closed) {
+            throw new IllegalStateException("Already closed.");
+        }
+        int newEnd = (end + 1) % buffer.length;
+        if (newEnd == start) {
+            //overflow:
+            int[] newBuffer = new int[buffer.length * 2];
+            int rightPart = (end > start ? end : buffer.length) - start;
+            int leftPart = end > start ? 0 : start - 1;
+            System.arraycopy(buffer, start, newBuffer, 0, rightPart);
+            System.arraycopy(buffer, 0, newBuffer, rightPart, leftPart);
+            buffer = newBuffer;
+            start = 0;
+            end = rightPart + leftPart;
+            newEnd = end + 1;
+        }
+        buffer[end] = b;
+        end = newEnd;
+        notifyAll();
+    }
+
+    @Override
+    public synchronized void close() {
+        closed = true;
+        notifyAll();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteCodes.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jshell.execution;
+
+/**
+ * Communication constants shared between the main process and the remote
+ * execution process.  These are not enums to allow for future expansion, and
+ * remote/local of different versions.
+ *
+ * @author Robert Field
+ */
+class RemoteCodes {
+
+    /**
+     * Command prefix markers.
+     */
+    static final int COMMAND_PREFIX = 0xC03DC03D;
+
+    // Command codes
+
+    /**
+     * Exit the the agent.
+     */
+    static final String CMD_CLOSE          = "CMD_CLOSE";
+    /**
+     * Load classes.
+     */
+    static final String CMD_LOAD           = "CMD_LOAD";
+    /**
+     * Redefine classes.
+     */
+    static final String CMD_REDEFINE       = "CMD_REDEFINE";
+    /**
+     * Invoke a method.
+     */
+    static final String CMD_INVOKE         = "CMD_INVOKE";
+    /**
+     * Retrieve the value of a variable.
+     */
+    static final String CMD_VAR_VALUE      = "CMD_VAR_VALUE";
+    /**
+     * Add to the class-path.
+     */
+    static final String CMD_ADD_CLASSPATH  = "CMD_ADD_CLASSPATH";
+    /**
+     * Set the class-path.
+     */
+    static final String CMD_SET_CLASSPATH  = "CMD_SET_CLASSPATH";
+    /**
+     * Stop an invoke.
+     */
+    static final String CMD_STOP           = "CMD_STOP";
+
+    // Return result codes
+
+    /**
+     * The command succeeded.
+     */
+    static final int RESULT_SUCCESS                 = 100;
+    /**
+     * Unbidden execution engine termination.
+     */
+    static final int RESULT_TERMINATED              = 101;
+    /**
+     * Command not implemented.
+     */
+    static final int RESULT_NOT_IMPLEMENTED         = 102;
+    /**
+     * The command failed.
+     */
+    static final int RESULT_INTERNAL_PROBLEM        = 103;
+    /**
+     * User exception encountered.
+     */
+    static final int RESULT_USER_EXCEPTION          = 104;
+    /**
+     * Corralled code exception encountered.
+     */
+    static final int RESULT_CORRALLED               = 105;
+    /**
+     * Exception encountered during class load/redefine.
+     */
+    static final int RESULT_CLASS_INSTALL_EXCEPTION = 106;
+    /**
+     * The invoke has been stopped.
+     */
+    static final int RESULT_STOPPED                 = 107;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.net.Socket;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+import jdk.jshell.spi.ExecutionControl;
+import static jdk.jshell.execution.Util.forwardExecutionControlAndIO;
+
+/**
+ * The remote agent runs in the execution process (separate from the main JShell
+ * process). This agent loads code over a socket from the main JShell process,
+ * executes the code, and other misc, Specialization of
+ * {@link DirectExecutionControl} which adds stop support controlled by
+ * an external process. Designed to work with {@link JDIDefaultExecutionControl}.
+ *
+ * @author Jan Lahoda
+ * @author Robert Field
+ */
+public class RemoteExecutionControl extends DirectExecutionControl implements ExecutionControl {
+
+    /**
+     * Launch the agent, connecting to the JShell-core over the socket specified
+     * in the command-line argument.
+     *
+     * @param args standard command-line arguments, expectation is the socket
+     * number is the only argument
+     * @throws Exception any unexpected exception
+     */
+    public static void main(String[] args) throws Exception {
+        String loopBack = null;
+        Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
+        InputStream inStream = socket.getInputStream();
+        OutputStream outStream = socket.getOutputStream();
+        Map<String, Consumer<OutputStream>> chans = new HashMap<>();
+        chans.put("out", st -> System.setOut(new PrintStream(st, true)));
+        chans.put("err", st -> System.setErr(new PrintStream(st, true)));
+        forwardExecutionControlAndIO(new RemoteExecutionControl(), inStream, outStream, chans);
+    }
+
+    // These three variables are used by the main JShell process in interrupting
+    // the running process.  Access is via JDI, so the reference is not visible
+    // to code inspection.
+    private boolean inClientCode; // Queried by the main process (in superclass)
+    private boolean expectingStop; // Set by the main process
+// Set by the main process
+
+    // thrown by the main process via JDI:
+    private final StopExecutionException stopException = new StopExecutionException();
+
+    /**
+     * Creates an instance, delegating loader operations to the specified
+     * delegate.
+     *
+     * @param loaderDelegate the delegate to handle loading classes
+     */
+    public RemoteExecutionControl(LoaderDelegate loaderDelegate) {
+        super(loaderDelegate);
+    }
+
+    /**
+     * Create an instance using the default class loading.
+     */
+    public RemoteExecutionControl() {
+    }
+
+    @Override
+    public void stop() throws EngineTerminationException, InternalException {
+        // handled by JDI
+    }
+
+    // Overridden only so this stack frame is seen
+    @Override
+    protected String invoke(Method doitMethod) throws Exception {
+        return super.invoke(doitMethod);
+    }
+
+    // Overridden only so this stack frame is seen
+    @Override
+    public String varValue(String className, String varName) throws RunException, EngineTerminationException, InternalException {
+        return super.varValue(className, varName);
+    }
+
+    @Override
+    protected String throwConvertedInvocationException(Throwable cause) throws RunException, InternalException {
+        if (cause instanceof StopExecutionException) {
+            expectingStop = false;
+            throw new StoppedException();
+        } else {
+            return super.throwConvertedInvocationException(cause);
+        }
+    }
+
+    @Override
+    protected String throwConvertedOtherException(Throwable ex) throws RunException, InternalException {
+        if (ex instanceof StopExecutionException ||
+                 ex.getCause() instanceof StopExecutionException) {
+            expectingStop = false;
+            throw new StoppedException();
+        }
+        return super.throwConvertedOtherException(ex);
+    }
+
+    @Override
+    protected void clientCodeEnter() {
+        expectingStop = false;
+        inClientCode = true;
+    }
+
+    @Override
+    protected void clientCodeLeave() throws InternalException {
+        inClientCode = false;
+        while (expectingStop) {
+            try {
+                Thread.sleep(0);
+            } catch (InterruptedException ex) {
+                throw new InternalException("*** Sleep interrupted while waiting for stop exception: " + ex);
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")             // serialVersionUID intentionally omitted
+    private class StopExecutionException extends ThreadDeath {
+
+        @Override
+        public synchronized Throwable fillInStackTrace() {
+            return this;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import jdk.jshell.JShellException;
+import jdk.jshell.spi.ExecutionControl;
+import static jdk.jshell.execution.RemoteCodes.*;
+
+/**
+ * An implementation of the {@link jdk.jshell.spi.ExecutionControl}
+ * execution engine SPI which streams requests to a remote agent where
+ * execution takes place.
+ *
+ * @author Robert Field
+ */
+public class StreamingExecutionControl implements ExecutionControl {
+
+    private final ObjectOutput out;
+    private final ObjectInput in;
+
+    /**
+     * Creates an instance.
+     *
+     * @param out the output for commands
+     * @param in the input for command responses
+     */
+    public StreamingExecutionControl(ObjectOutput out, ObjectInput in) {
+        this.out = out;
+        this.in = in;
+    }
+
+    @Override
+    public void load(ClassBytecodes[] cbcs)
+            throws ClassInstallException, NotImplementedException, EngineTerminationException {
+        try {
+            // Send a load command to the remote agent.
+            writeCommand(CMD_LOAD);
+            out.writeObject(cbcs);
+            out.flush();
+            // Retrieve and report results from the remote agent.
+            readAndReportClassInstallResult();
+        } catch (IOException ex) {
+            throw new EngineTerminationException("Exception writing remote load: " + ex);
+        }
+    }
+
+    @Override
+    public void redefine(ClassBytecodes[] cbcs)
+            throws ClassInstallException, NotImplementedException, EngineTerminationException {
+        try {
+            // Send a load command to the remote agent.
+            writeCommand(CMD_REDEFINE);
+            out.writeObject(cbcs);
+            out.flush();
+            // Retrieve and report results from the remote agent.
+            readAndReportClassInstallResult();
+        } catch (IOException ex) {
+            throw new EngineTerminationException("Exception writing remote redefine: " + ex);
+        }
+    }
+
+    @Override
+    public String invoke(String classname, String methodname)
+            throws RunException, EngineTerminationException, InternalException {
+        try {
+            // Send the invoke command to the remote agent.
+            writeCommand(CMD_INVOKE);
+            out.writeUTF(classname);
+            out.writeUTF(methodname);
+            out.flush();
+            // Retrieve and report results from the remote agent.
+            readAndReportExecutionResult();
+            String result = in.readUTF();
+            return result;
+        } catch (IOException ex) {
+            throw new EngineTerminationException("Exception writing remote invoke: " + ex);
+        }
+    }
+
+    @Override
+    public String varValue(String classname, String varname)
+            throws RunException, EngineTerminationException, InternalException {
+        try {
+            // Send the variable-value command to the remote agent.
+            writeCommand(CMD_VAR_VALUE);
+            out.writeUTF(classname);
+            out.writeUTF(varname);
+            out.flush();
+            // Retrieve and report results from the remote agent.
+            readAndReportExecutionResult();
+            String result = in.readUTF();
+            return result;
+        } catch (IOException ex) {
+            throw new EngineTerminationException("Exception writing remote varValue: " + ex);
+        }
+    }
+
+
+    @Override
+    public void addToClasspath(String path)
+            throws EngineTerminationException, InternalException {
+        try {
+            // Send the classpath addition command to the remote agent.
+            writeCommand(CMD_ADD_CLASSPATH);
+            out.writeUTF(path);
+            out.flush();
+            // Retrieve and report results from the remote agent.
+            readAndReportClassSimpleResult();
+        } catch (IOException ex) {
+            throw new EngineTerminationException("Exception writing remote add to classpath: " + ex);
+        }
+    }
+
+    @Override
+    public void setClasspath(String path)
+            throws EngineTerminationException, InternalException {
+        try {
+            // Send the classpath addition command to the remote agent.
+            writeCommand(CMD_SET_CLASSPATH);
+            out.writeUTF(path);
+            out.flush();
+            // Retrieve and report results from the remote agent.
+            readAndReportClassSimpleResult();
+        } catch (IOException ex) {
+            throw new EngineTerminationException("Exception writing remote set classpath: " + ex);
+        }
+    }
+
+    @Override
+    public void stop()
+            throws EngineTerminationException, InternalException {
+        try {
+            // Send the variable-value command to the remote agent.
+            writeCommand(CMD_STOP);
+            out.flush();
+        } catch (IOException ex) {
+            throw new EngineTerminationException("Exception writing remote stop: " + ex);
+        }
+    }
+
+    @Override
+    public Object extensionCommand(String command, Object arg)
+            throws RunException, EngineTerminationException, InternalException {
+        try {
+            writeCommand(command);
+            out.writeObject(arg);
+            out.flush();
+            // Retrieve and report results from the remote agent.
+            readAndReportExecutionResult();
+            Object result = in.readObject();
+            return result;
+        } catch (IOException | ClassNotFoundException ex) {
+            throw new EngineTerminationException("Exception transmitting remote extensionCommand: "
+                    + command + " -- " + ex);
+        }
+    }
+
+    /**
+     * Closes the execution engine. Send an exit command to the remote agent.
+     */
+    @Override
+    public void close() {
+        try {
+            writeCommand(CMD_CLOSE);
+            out.flush();
+        } catch (IOException ex) {
+            // ignore;
+        }
+    }
+
+    private void writeCommand(String cmd) throws IOException {
+        out.writeInt(COMMAND_PREFIX);
+        out.writeUTF(cmd);
+    }
+
+    /**
+     * Reports results from a remote agent command that does not expect
+     * exceptions.
+     */
+    private void readAndReportClassSimpleResult() throws EngineTerminationException, InternalException {
+        try {
+            int status = in.readInt();
+            switch (status) {
+                case RESULT_SUCCESS:
+                    return;
+                case RESULT_NOT_IMPLEMENTED: {
+                    String message = in.readUTF();
+                    throw new NotImplementedException(message);
+                }
+                case RESULT_INTERNAL_PROBLEM: {
+                    String message = in.readUTF();
+                    throw new InternalException(message);
+                }
+                case RESULT_TERMINATED: {
+                    String message = in.readUTF();
+                    throw new EngineTerminationException(message);
+                }
+                default: {
+                    throw new EngineTerminationException("Bad remote result code: " + status);
+                }
+            }
+        } catch (IOException ex) {
+            throw new EngineTerminationException(ex.toString());
+        }
+    }
+
+    /**
+     * Reports results from a remote agent command that does not expect
+     * exceptions.
+     */
+    private void readAndReportClassInstallResult() throws ClassInstallException,
+            NotImplementedException, EngineTerminationException {
+        try {
+            int status = in.readInt();
+            switch (status) {
+                case RESULT_SUCCESS:
+                    return;
+                case RESULT_NOT_IMPLEMENTED: {
+                    String message = in.readUTF();
+                    throw new NotImplementedException(message);
+                }
+                case RESULT_CLASS_INSTALL_EXCEPTION: {
+                    String message = in.readUTF();
+                    boolean[] loaded = (boolean[]) in.readObject();
+                    throw new ClassInstallException(message, loaded);
+                }
+                case RESULT_TERMINATED: {
+                    String message = in.readUTF();
+                    throw new EngineTerminationException(message);
+                }
+                default: {
+                    throw new EngineTerminationException("Bad remote result code: " + status);
+                }
+            }
+        } catch (IOException | ClassNotFoundException ex) {
+            throw new EngineTerminationException(ex.toString());
+        }
+    }
+
+    /**
+     * Reports results from a remote agent command that expects runtime
+     * exceptions.
+     *
+     * @return true if successful
+     * @throws IOException if the connection has dropped
+     * @throws JShellException {@link jdk.jshell.EvalException}, if a user
+     * exception was encountered on invoke;
+     * {@link jdk.jshell.UnresolvedReferenceException}, if an unresolved
+     * reference was encountered
+     * @throws java.lang.ClassNotFoundException
+     */
+    private void readAndReportExecutionResult() throws RunException,
+            EngineTerminationException, InternalException {
+        try {
+            int status = in.readInt();
+            switch (status) {
+                case RESULT_SUCCESS:
+                    return;
+                case RESULT_NOT_IMPLEMENTED: {
+                    String message = in.readUTF();
+                    throw new NotImplementedException(message);
+                }
+                case RESULT_USER_EXCEPTION: {
+                    // A user exception was encountered.
+                    String message = in.readUTF();
+                    String exceptionClassName = in.readUTF();
+                    StackTraceElement[] elems = (StackTraceElement[]) in.readObject();
+                    throw new UserException(message, exceptionClassName, elems);
+                }
+                case RESULT_CORRALLED: {
+                    // An unresolved reference was encountered.
+                    int id = in.readInt();
+                    StackTraceElement[] elems = (StackTraceElement[]) in.readObject();
+                    ResolutionException re = new ResolutionException(id, elems);
+                    throw re;
+                }
+                case RESULT_STOPPED: {
+                    // Execution was aborted by the stop()
+                    throw new StoppedException();
+                }
+                case RESULT_INTERNAL_PROBLEM: {
+                    // An internal error has occurred.
+                    String message = in.readUTF();
+                    throw new InternalException(message);
+                }
+                case RESULT_TERMINATED: {
+                    String message = in.readUTF();
+                    throw new EngineTerminationException(message);
+                }
+                default: {
+                    throw new EngineTerminationException("Bad remote result code: " + status);
+                }
+            }
+        } catch (IOException | ClassNotFoundException ex) {
+            throw new EngineTerminationException(ex.toString());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import jdk.jshell.spi.ExecutionEnv;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Consumer;
+import com.sun.jdi.VirtualMachine;
+import jdk.jshell.spi.ExecutionControl;
+
+
+/**
+ * Miscellaneous utility methods for setting-up implementations of
+ * {@link ExecutionControl}. Particularly implementations with remote
+ * execution.
+ *
+ * @author Jan Lahoda
+ * @author Robert Field
+ */
+public class Util {
+
+    // never instanciated
+    private Util() {}
+
+    /**
+     * Create a composite {@link ExecutionControl.Generator} instance that, when
+     * generating, will try each specified generator until successfully creating
+     * an {@link ExecutionControl} instance, or, if all fail, will re-throw the
+     * first exception.
+     *
+     * @param gec0 the first instance to try
+     * @param gecs the second through Nth instance to try
+     * @return the fail-over generator
+     */
+    public static ExecutionControl.Generator failOverExecutionControlGenerator(
+            ExecutionControl.Generator gec0, ExecutionControl.Generator... gecs) {
+        return (ExecutionEnv env) -> {
+            Throwable thrown;
+            try {
+                return gec0.generate(env);
+            } catch (Throwable ex) {
+                thrown = ex;
+            }
+            for (ExecutionControl.Generator gec : gecs) {
+                try {
+                    return gec.generate(env);
+                } catch (Throwable ignore) {
+                    // only care about the first, and only if they all fail
+                }
+            }
+            throw thrown;
+        };
+    }
+
+    /**
+     * Forward commands from the input to the specified {@link ExecutionControl}
+     * instance, then responses back on the output.
+     * @param ec the direct instance of {@link ExecutionControl} to process commands
+     * @param in the command input
+     * @param out the command response output
+     */
+    public static void forwardExecutionControl(ExecutionControl ec,
+            ObjectInput in, ObjectOutput out) {
+        new ExecutionControlForwarder(ec, in, out).commandLoop();
+    }
+
+    /**
+     * Forward commands from the input to the specified {@link ExecutionControl}
+     * instance, then responses back on the output.
+     * @param ec the direct instance of {@link ExecutionControl} to process commands
+     * @param inStream the stream from which to create the command input
+     * @param outStream the stream that will carry {@code System.out},
+     * {@code System.err}, any specified auxiliary channels, and the
+     * command response output.
+     * @param streamMap a map between names of additional streams to carry and setters
+     * for the stream
+     * @throws IOException if there are errors using the passed streams
+     */
+    public static void forwardExecutionControlAndIO(ExecutionControl ec,
+            InputStream inStream, OutputStream outStream,
+            Map<String, Consumer<OutputStream>> streamMap) throws IOException {
+        ObjectInputStream cmdIn = new ObjectInputStream(inStream);
+        for (Entry<String, Consumer<OutputStream>> e : streamMap.entrySet()) {
+            e.getValue().accept(multiplexingOutputStream(e.getKey(), outStream));
+        }
+        ObjectOutputStream cmdOut = new ObjectOutputStream(multiplexingOutputStream("command", outStream));
+        forwardExecutionControl(ec, cmdIn, cmdOut);
+    }
+
+    static OutputStream multiplexingOutputStream(String label, OutputStream outputStream) {
+        return new MultiplexingOutputStream(label, outputStream);
+    }
+
+    /**
+     * Reads from an InputStream which has been packetized and write its contents
+     * to the out and err OutputStreams; Copies the command stream.
+     * @param input the packetized input stream
+     * @param streamMap a map between stream names and the output streams to forward
+     * @return the command stream
+     * @throws IOException if setting up the streams raised an exception
+     */
+    public static ObjectInput remoteInput(InputStream input,
+            Map<String, OutputStream> streamMap) throws IOException {
+        PipeInputStream commandIn = new PipeInputStream();
+        new DemultiplexInput(input, commandIn, streamMap).start();
+        return new ObjectInputStream(commandIn);
+    }
+
+    /**
+     * Monitor the JDI event stream for {@link com.sun.jdi.event.VMDeathEvent}
+     * and {@link com.sun.jdi.event.VMDisconnectEvent}. If encountered, invokes
+     * {@code unbiddenExitHandler}.
+     *
+     * @param vm the virtual machine to check
+     * @param unbiddenExitHandler the handler, which will accept the exit
+     * information
+     */
+    public static void detectJDIExitEvent(VirtualMachine vm, Consumer<String> unbiddenExitHandler) {
+        if (vm.canBeModified()) {
+            new JDIEventHandler(vm, unbiddenExitHandler).start();
+        }
+    }
+
+    /**
+     * Creates a Thread that will ship all input to the remote agent.
+     *
+     * @param inputStream the user input
+     * @param outStream the input to the remote agent
+     * @param handler a failure handler
+     */
+    public static void forwardInputToRemote(final InputStream inputStream,
+            final OutputStream outStream, final Consumer<Exception> handler) {
+        Thread thr = new Thread("input reader") {
+            @Override
+            public void run() {
+                try {
+                    byte[] buf = new byte[256];
+                    int cnt;
+                    while ((cnt = inputStream.read(buf)) != -1) {
+                        outStream.write(buf, 0, cnt);
+                        outStream.flush();
+                    }
+                } catch (Exception ex) {
+                    handler.accept(ex);
+                }
+            }
+        };
+        thr.setPriority(Thread.MAX_PRIORITY - 1);
+        thr.start();
+    }
+
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java	Wed Jul 05 22:00:06 2017 +0200
@@ -22,62 +22,152 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package jdk.jshell.spi;
 
-import java.util.Collection;
-import jdk.jshell.JShellException;
+import java.io.Serializable;
 
 /**
- * This interface specifies the functionality that must provided to implement
- * a pluggable JShell execution engine.
+ * This interface specifies the functionality that must provided to implement a
+ * pluggable JShell execution engine.
  * <p>
- * The audience for this Service Provider Interface is engineers
- * wishing to implement their own version of the execution engine in support
- * of the JShell API.  This is NOT a part of the JShell API.
+ * The audience for this Service Provider Interface is engineers wishing to
+ * implement their own version of the execution engine in support of the JShell
+ * API.
  * <p>
- * A Snippet is compiled into code wrapped in a 'wrapper class'.  The execution
- * engine is used by the core JShell implementation to load and, for
- * executable Snippets, execute the Snippet.
+ * A Snippet is compiled into code wrapped in a 'wrapper class'. The execution
+ * engine is used by the core JShell implementation to load and, for executable
+ * Snippets, execute the Snippet.
  * <p>
  * Methods defined in this interface should only be called by the core JShell
  * implementation.
  * <p>
- * To install an instance of ExecutionControl, it is passed to
- * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl) }.
+ * To install an {@code ExecutionControl}, its {@code Generator} is passed to
+ * {@link jdk.jshell.JShell.Builder#executionEngine(ExecutionControl.Generator)  }.
  */
 public interface ExecutionControl {
 
     /**
-     * Represents the current status of a class in the execution engine.
+     * Defines a functional interface for creating {@link ExecutionControl}
+     * instances.
      */
-    public enum ClassStatus {
-        /**
-         * Class is not known to the execution engine (not loaded).
-         */
-        UNKNOWN,
-
-        /**
-         * Class is loaded, but the loaded/redefined bytes do not match those
-         * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }.
-         */
-        NOT_CURRENT,
+    public interface Generator {
 
         /**
-         * Class is loaded and loaded/redefined bytes match those
-         * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }.
+         * Generates an execution engine, given an execution environment.
+         *
+         * @param env the context in which the {@link ExecutionControl} is to
+         * be created
+         * @return the created instance
+         * @throws Throwable if problems occurred
          */
-        CURRENT
-    };
+        ExecutionControl generate(ExecutionEnv env) throws Throwable;
+    }
+
+    /**
+     * Attempts to load new classes.
+     *
+     * @param cbcs the class name and bytecodes to load
+     * @throws ClassInstallException exception occurred loading the classes,
+     * some or all were not loaded
+     * @throws NotImplementedException if not implemented
+     * @throws EngineTerminationException the execution engine has terminated
+     */
+    void load(ClassBytecodes[] cbcs)
+            throws ClassInstallException, NotImplementedException, EngineTerminationException;
+
+    /**
+     * Attempts to redefine previously loaded classes.
+     *
+     * @param cbcs the class name and bytecodes to redefine
+     * @throws ClassInstallException exception occurred redefining the classes,
+     * some or all were not redefined
+     * @throws NotImplementedException if not implemented
+     * @throws EngineTerminationException the execution engine has terminated
+     */
+    void redefine(ClassBytecodes[] cbcs)
+            throws ClassInstallException, NotImplementedException, EngineTerminationException;
+
+    /**
+     * Invokes an executable Snippet by calling a method on the specified
+     * wrapper class. The method must have no arguments and return String.
+     *
+     * @param className the class whose method should be invoked
+     * @param methodName the name of method to invoke
+     * @return the result of the execution or null if no result
+     * @throws UserException the invoke raised a user exception
+     * @throws ResolutionException the invoke attempted to directly or
+     * indirectly invoke an unresolved snippet
+     * @throws StoppedException if the {@code invoke()} was canceled by
+     * {@link ExecutionControl#stop}
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws InternalException an internal problem occurred
+     */
+    String invoke(String className, String methodName)
+            throws RunException, EngineTerminationException, InternalException;
 
     /**
-     * Initializes the instance. No methods in this interface can be called
-     * before this.
+     * Returns the value of a variable.
+     *
+     * @param className the name of the wrapper class of the variable
+     * @param varName the name of the variable
+     * @return the value of the variable
+     * @throws UserException formatting the value raised a user exception
+     * @throws ResolutionException formatting the value attempted to directly or
+     * indirectly invoke an unresolved snippet
+     * @throws StoppedException if the formatting the value was canceled by
+     * {@link ExecutionControl#stop}
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws InternalException an internal problem occurred
+     */
+    String varValue(String className, String varName)
+            throws RunException, EngineTerminationException, InternalException;
+
+    /**
+     * Adds the path to the execution class path.
+     *
+     * @param path the path to add
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws InternalException an internal problem occurred
+     */
+    void addToClasspath(String path)
+            throws EngineTerminationException, InternalException;
+
+    /**
+     * Sets the execution class path to the specified path.
      *
-     * @param env the execution environment information provided by JShell
-     * @throws Exception if the instance is unable to initialize
+     * @param path the path to add
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws InternalException an internal problem occurred
+     */
+    void setClasspath(String path)
+            throws EngineTerminationException, InternalException;
+
+    /**
+     * Interrupts a running invoke.
+     *
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws InternalException an internal problem occurred
      */
-    void start(ExecutionEnv env) throws Exception;
+    void stop()
+            throws EngineTerminationException, InternalException;
+
+    /**
+     * Run a non-standard command (or a standard command from a newer version).
+     *
+     * @param command the non-standard command
+     * @param arg the commands argument
+     * @return the commands return value
+     * @throws UserException the command raised a user exception
+     * @throws ResolutionException the command attempted to directly or
+     * indirectly invoke an unresolved snippet
+     * @throws StoppedException if the command was canceled by
+     * {@link ExecutionControl#stop}
+     * @throws EngineTerminationException the execution engine has terminated
+     * @throws NotImplementedException if not implemented
+     * @throws InternalException an internal problem occurred
+     */
+    Object extensionCommand(String command, Object arg)
+            throws RunException, EngineTerminationException, InternalException;
 
     /**
      * Shuts down this execution engine. Implementation should free all
@@ -88,67 +178,206 @@
     void close();
 
     /**
-     * Adds the path to the execution class path.
-     *
-     * @param path the path to add
-     * @return true if successful
+     * Bundles class name with class bytecodes.
      */
-    boolean addToClasspath(String path);
+    public static final class ClassBytecodes implements Serializable {
+
+        private static final long serialVersionUID = 0xC1A55B47EC0DE5L;
+        private final String name;
+        private final byte[] bytecodes;
+
+        /**
+         * Creates a name/bytecode pair.
+         * @param name the class name
+         * @param bytecodes the class bytecodes
+         */
+        public ClassBytecodes(String name, byte[] bytecodes) {
+            this.name = name;
+            this.bytecodes = bytecodes;
+        }
+
+        /**
+         * The bytecodes for the class.
+         *
+         * @return the bytecodes
+         */
+        public byte[] bytecodes() {
+            return bytecodes;
+        }
+
+        /**
+         * The class name.
+         *
+         * @return the class name
+         */
+        public String name() {
+            return name;
+        }
+    }
 
     /**
-     * Invokes an executable Snippet by calling a method on the specified
-     * wrapper class. The method must have no arguments and return String.
-     *
-     * @param classname the class whose method should be invoked
-     * @param methodname the name of method to invoke
-     * @return the result of the execution or null if no result
-     * @throws JShellException if a user exception if thrown,
-     * {@link jdk.jshell.EvalException EvalException} will be thrown; if an
-     * unresolved reference is encountered,
-     * {@link jdk.jshell.UnresolvedReferenceException UnresolvedReferenceException}
-     * will be thrown
+     * The abstract base of all {@code ExecutionControl} exceptions.
      */
-    String invoke(String classname, String methodname) throws JShellException;
+    public static abstract class ExecutionControlException extends Exception {
+
+        private static final long serialVersionUID = 1L;
+
+        public ExecutionControlException(String message) {
+            super(message);
+        }
+    }
 
     /**
-     * Attempts to load new classes. Class bytes are retrieved from
-     * {@link ExecutionEnv#getClassBytes(java.lang.String) }
-     *
-     * @param classes list of class names to load
-     * @return true if load succeeded
+     * Unbidden execution engine termination has occurred.
+     */
+    public static class EngineTerminationException extends ExecutionControlException {
+
+        private static final long serialVersionUID = 1L;
+
+        public EngineTerminationException(String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * The command is not implemented.
      */
-    boolean load(Collection<String> classes);
+    public static class NotImplementedException extends InternalException {
+
+        private static final long serialVersionUID = 1L;
+
+        public NotImplementedException(String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * An internal problem has occurred.
+     */
+    public static class InternalException extends ExecutionControlException {
+
+        private static final long serialVersionUID = 1L;
+
+        public InternalException(String message) {
+            super(message);
+        }
+    }
 
     /**
-     * Attempts to redefine previously loaded classes. Class bytes are retrieved
-     * from {@link ExecutionEnv#getClassBytes(java.lang.String) }
-     *
-     * @param classes list of class names to redefine
-     * @return true if redefine succeeded
+     * A class install (load or redefine) encountered a problem.
      */
-    boolean redefine(Collection<String> classes);
+    public static class ClassInstallException extends ExecutionControlException {
+
+        private static final long serialVersionUID = 1L;
+
+        private final boolean[] installed;
+
+        public ClassInstallException(String message, boolean[] installed) {
+            super(message);
+            this.installed = installed;
+        }
+
+        /**
+         * Indicates which of the passed classes were successfully
+         * loaded/redefined.
+         * @return a one-to-one array with the {@link ClassBytecodes}{@code[]}
+         * array -- {@code true} if installed
+         */
+        public boolean[] installed() {
+            return installed;
+        }
+    }
+
+    /**
+     * The abstract base of of exceptions specific to running user code.
+     */
+    public static abstract class RunException extends ExecutionControlException {
+
+        private static final long serialVersionUID = 1L;
+
+        private RunException(String message) {
+            super(message);
+        }
+    }
 
     /**
-     * Queries if the class is loaded and the class bytes are current.
-     *
-     * @param classname name of the wrapper class to query
-     * @return {@code UNKNOWN} if the class is not loaded; {@code CURRENT} if
-     * the loaded/redefined bytes are equal to the most recent bytes for this
-     * wrapper class; otherwise {@code NOT_CURRENT}
+     * A 'normal' user exception occurred.
      */
-    ClassStatus getClassStatus(String classname);
+    public static class UserException extends RunException {
+
+        private static final long serialVersionUID = 1L;
+
+        private final String causeExceptionClass;
+
+        public UserException(String message, String causeExceptionClass, StackTraceElement[] stackElements) {
+            super(message);
+            this.causeExceptionClass = causeExceptionClass;
+            this.setStackTrace(stackElements);
+        }
+
+        /**
+         * Returns the class of the user exception.
+         * @return the name of the user exception class
+         */
+        public String causeExceptionClass() {
+            return causeExceptionClass;
+        }
+    }
 
     /**
-     * Interrupt a running invoke.
+     * An exception indicating that a {@code DeclarationSnippet} with unresolved
+     * references has been encountered.
+     * <p>
+     * Contrast this with the initiating {@link SPIResolutionException}
+     * (a {@code RuntimeException}) which is embedded in generated corralled
+     * code.  Also, contrast this with
+     * {@link jdk.jshell.UnresolvedReferenceException} the high-level
+     * exception (with {@code DeclarationSnippet} reference) provided in the
+     * main API.
      */
-    void stop();
+    public static class ResolutionException extends RunException {
+
+        private static final long serialVersionUID = 1L;
+
+        private final int id;
+
+        /**
+         * Constructs an exception indicating that a {@code DeclarationSnippet}
+         * with unresolved references has been encountered.
+         *
+         * @param id An internal identifier of the specific method
+         * @param stackElements the stack trace
+         */
+        public ResolutionException(int id, StackTraceElement[] stackElements) {
+            super("resolution exception: " + id);
+            this.id = id;
+            this.setStackTrace(stackElements);
+        }
+
+        /**
+         * Retrieves the internal identifier of the unresolved identifier.
+         *
+         * @return the internal identifier
+         */
+        public int id() {
+            return id;
+        }
+    }
 
     /**
-     * Returns the value of a variable.
-     *
-     * @param classname the name of the wrapper class of the variable
-     * @param varname the name of the variable
-     * @return the value of the variable
+     * An exception indicating that an
+     * {@link ExecutionControl#invoke(java.lang.String, java.lang.String) }
+     * (or theoretically a
+     * {@link ExecutionControl#varValue(java.lang.String, java.lang.String) })
+     * has been interrupted by a {@link ExecutionControl#stop() }.
      */
-    String varValue(String classname, String varname);
+    public static class StoppedException extends RunException {
+
+        private static final long serialVersionUID = 1L;
+
+        public StoppedException() {
+            super("stopped by stop()");
+        }
+    }
+
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionEnv.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionEnv.java	Wed Jul 05 22:00:06 2017 +0200
@@ -28,14 +28,11 @@
 import java.io.InputStream;
 import java.io.PrintStream;
 import java.util.List;
-import jdk.jshell.EvalException;
 import jdk.jshell.JShell;
-import jdk.jshell.UnresolvedReferenceException;
 
 /**
  * Functionality made available to a pluggable JShell execution engine.  It is
- * provided to the execution engine by the core JShell implementation calling
- * {@link ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }.
+ * provided to the execution engine by the core JShell implementation.
  * <p>
  * This interface is designed to provide the access to core JShell functionality
  * needed to implement ExecutionControl.
@@ -66,11 +63,6 @@
     PrintStream userErr();
 
     /**
-     * @return the JShell instance
-     */
-    JShell state();
-
-    /**
      * Returns the additional VM options to be used when launching the remote
      * JVM. This is advice to the execution engine.
      * <p>
@@ -81,47 +73,8 @@
     List<String> extraRemoteVMOptions();
 
     /**
-     * Retrieves the class file bytes for the specified wrapper class.
-     *
-     * @param className the name of the wrapper class
-     * @return the current class file bytes as a byte array
-     */
-    byte[] getClassBytes(String className);
-
-    /**
-     * Creates an {@code EvalException} corresponding to a user exception. An
-     * user exception thrown during
-     * {@link ExecutionControl#invoke(java.lang.String, java.lang.String) }
-     * should be converted to an {@code EvalException} using this method.
-     *
-     * @param message the exception message to use (from the user exception)
-     * @param exceptionClass the class name of the user exception
-     * @param stackElements the stack trace elements to install
-     * @return a user API EvalException for the user exception
-     */
-    EvalException createEvalException(String message, String exceptionClass,
-            StackTraceElement[] stackElements);
-
-    /**
-     * Creates an {@code UnresolvedReferenceException} for the Snippet identifed
-     * by the specified identifier. An {@link SPIResolutionException} thrown
-     * during {@link ExecutionControl#invoke(java.lang.String, java.lang.String) }
-     * should be converted to an {@code UnresolvedReferenceException} using
-     * this method.
-     * <p>
-     * The identifier is an internal id, different from the id in the API. This
-     * internal id is returned by {@link SPIResolutionException#id()}.
-     *
-     * @param id the internal integer identifier
-     * @param stackElements the stack trace elements to install
-     * @return an {@code UnresolvedReferenceException} for the unresolved
-     * reference
-     */
-    UnresolvedReferenceException createUnresolvedReferenceException(int id,
-            StackTraceElement[] stackElements);
-
-    /**
      * Reports that the execution engine has shutdown.
      */
     void closeDown();
+
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/SPIResolutionException.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/SPIResolutionException.java	Wed Jul 05 22:00:06 2017 +0200
@@ -33,9 +33,6 @@
  * <p>
  * This exception is seen by the execution engine, but not seen by
  * the end user nor through the JShell API.
- *
- * @see ExecutionEnv#createUnresolvedReferenceException(int,
- * java.lang.StackTraceElement[])
  */
 @SuppressWarnings("serial")             // serialVersionUID intentionally omitted
 public class SPIResolutionException extends RuntimeException {
@@ -57,11 +54,9 @@
     }
 
     /**
-     * Retrieves the internal identifer of the unresolved identifer.
+     * Retrieves the internal identifier of the unresolved identifier.
      *
-     * @return the internal identifer
-     * @see ExecutionEnv#createUnresolvedReferenceException(int,
-     * java.lang.StackTraceElement[])
+     * @return the internal identifier
      */
     public int id() {
         return id;
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/package-info.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/package-info.java	Wed Jul 05 22:00:06 2017 +0200
@@ -31,9 +31,9 @@
  * implementation includes a default execution engine (currently a remote
  * process which is JDI controlled).  By implementing the
  * {@link jdk.jshell.spi.ExecutionControl} interface and installing it with
- * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl) }
+ * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl.Generator) }
  * other execution engines can be used.
  *
- * @see jdk.jshell.execution jdk.jshell.execution for execution implementation support
+ * @see jdk.jshell.execution for execution implementation support
  */
 package jdk.jshell.spi;
--- a/langtools/test/jdk/jshell/ComputeFQNsTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/jdk/jshell/ComputeFQNsTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -76,7 +76,7 @@
         assertInferredFQNs("class X { ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
     }
 
-    @Test
+    @Test(enabled = false) //TODO 8161165
     public void testSuspendIndexing() throws Throwable {
         compiler.compile(outDir, "package test; public class FQNTest { }");
         String jarName = "test.jar";
--- a/langtools/test/jdk/jshell/FailOverExecutionControlTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/jdk/jshell/FailOverExecutionControlTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -23,23 +23,20 @@
 
 /*
  * @test
- * @bug 8131029
- * @summary Test that fail-over works for FailOverExecutionControl
- * @modules jdk.jshell/jdk.internal.jshell.jdi
+ * @bug 8131029 8160127 8159935
+ * @summary Test that fail-over works for fail-over ExecutionControl generators.
+ * @modules jdk.jshell/jdk.jshell.execution
  *          jdk.jshell/jdk.jshell.spi
  * @build KullaTesting ExecutionControlTestBase
  * @run testng FailOverExecutionControlTest
  */
 
-
-import java.util.Collection;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
-import jdk.internal.jshell.jdi.FailOverExecutionControl;
-import jdk.internal.jshell.jdi.JDIExecutionControl;
-import jdk.jshell.JShellException;
+import jdk.jshell.execution.JDIDefaultExecutionControl;
 import jdk.jshell.spi.ExecutionControl;
 import jdk.jshell.spi.ExecutionEnv;
+import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
 
 @Test
 public class FailOverExecutionControlTest extends ExecutionControlTestBase {
@@ -47,56 +44,16 @@
     @BeforeMethod
     @Override
     public void setUp() {
-        setUp(new FailOverExecutionControl(
-                new AlwaysFailingExecutionControl(),
-                new AlwaysFailingExecutionControl(),
-                new JDIExecutionControl()));
+        setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
+                new AlwaysFailingGenerator(),
+                new AlwaysFailingGenerator(),
+                JDIDefaultExecutionControl.launch())));
     }
 
-    class AlwaysFailingExecutionControl implements ExecutionControl {
-
-        @Override
-        public void start(ExecutionEnv env) throws Exception {
-            throw new UnsupportedOperationException("This operation intentionally broken.");
-        }
-
-        @Override
-        public void close() {
-            throw new UnsupportedOperationException("This operation intentionally broken.");
-        }
-
-        @Override
-        public boolean addToClasspath(String path) {
-            throw new UnsupportedOperationException("This operation intentionally broken.");
-        }
+    class AlwaysFailingGenerator implements ExecutionControl.Generator {
 
         @Override
-        public String invoke(String classname, String methodname) throws JShellException {
-            throw new UnsupportedOperationException("This operation intentionally broken.");
-        }
-
-        @Override
-        public boolean load(Collection<String> classes) {
-            throw new UnsupportedOperationException("This operation intentionally broken.");
-        }
-
-        @Override
-        public boolean redefine(Collection<String> classes) {
-            throw new UnsupportedOperationException("This operation intentionally broken.");
-        }
-
-        @Override
-        public ClassStatus getClassStatus(String classname) {
-            throw new UnsupportedOperationException("This operation intentionally broken.");
-        }
-
-        @Override
-        public void stop() {
-            throw new UnsupportedOperationException("This operation intentionally broken.");
-        }
-
-        @Override
-        public String varValue(String classname, String varname) {
+        public ExecutionControl generate(ExecutionEnv env) throws UnsupportedOperationException {
             throw new UnsupportedOperationException("This operation intentionally broken.");
         }
 
--- a/langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -23,9 +23,9 @@
 
 /*
  * @test
- * @bug 8131029
+ * @bug 8131029 8159935 8160127
  * @summary Tests for alternate JDI connector -- listening
- * @modules jdk.jshell/jdk.internal.jshell.jdi
+ * @modules jdk.jshell/jdk.jshell.execution
  * @build KullaTesting ExecutionControlTestBase
  * @run testng JDIListeningExecutionControlTest
  */
@@ -33,7 +33,7 @@
 
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
-import jdk.internal.jshell.jdi.JDIExecutionControl;
+import jdk.jshell.execution.JDIDefaultExecutionControl;
 
 @Test
 public class JDIListeningExecutionControlTest extends ExecutionControlTestBase {
@@ -41,6 +41,6 @@
     @BeforeMethod
     @Override
     public void setUp() {
-        setUp(new JDIExecutionControl(false));
+        setUp(builder -> builder.executionEngine(JDIDefaultExecutionControl.listen()));
     }
 }
--- a/langtools/test/jdk/jshell/KullaTesting.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/jdk/jshell/KullaTesting.java	Wed Jul 05 22:00:06 2017 +0200
@@ -73,7 +73,6 @@
 import static jdk.jshell.Snippet.Status.*;
 import static org.testng.Assert.*;
 import static jdk.jshell.Snippet.SubKind.METHOD_SUBKIND;
-import jdk.jshell.spi.ExecutionControl;
 
 public class KullaTesting {
 
@@ -158,10 +157,6 @@
         setUp(b -> {});
     }
 
-    public void setUp(ExecutionControl ec) {
-        setUp(b -> b.executionEngine(ec));
-    }
-
     public void setUp(Consumer<JShell.Builder> bc) {
         inStream = new TestingInputStream();
         outStream = new ByteArrayOutputStream();
--- a/langtools/test/jdk/jshell/LocalExecutionControl.java	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import jdk.jshell.spi.ExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
-import jdk.jshell.spi.SPIResolutionException;
-import jdk.jshell.EvalException;
-import jdk.jshell.UnresolvedReferenceException;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.security.CodeSource;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * An implementation of ExecutionControl which executes in the same JVM as the
- * JShell core.
- *
- * @author Grigory Ptashko
- */
-class LocalExecutionControl implements ExecutionControl {
-    private class REPLClassLoader extends URLClassLoader {
-        REPLClassLoader() {
-            super(new URL[0]);
-        }
-
-        @Override
-        protected Class<?> findClass(String name) throws ClassNotFoundException {
-            debug("findClass %s\n", name);
-            byte[] b = execEnv.getClassBytes(name);
-            if (b == null) {
-                return super.findClass(name);
-            }
-            return super.defineClass(name, b, 0, b.length, (CodeSource)null);
-        }
-
-        @Override
-        public void addURL(URL url) {
-            super.addURL(url);
-        }
-    }
-
-    private ExecutionEnv execEnv;
-    private final Object STOP_LOCK = new Object();
-    private boolean userCodeRunning = false;
-    private REPLClassLoader loader = new REPLClassLoader();
-    private final Map<String, Class<?>> klasses = new TreeMap<>();
-    private final Map<String, byte[]> classBytes = new HashMap<>();
-    private ThreadGroup execThreadGroup;
-
-    @Override
-    public void start(ExecutionEnv execEnv) throws Exception {
-        this.execEnv = execEnv;
-
-        debug("Process-local code snippets execution control started");
-    }
-
-    @Override
-    public void close() {
-    }
-
-    @Override
-    public boolean load(Collection<String> classes) {
-        try {
-            loadLocal(classes);
-
-            return true;
-        } catch (ClassNotFoundException | ClassCastException ex) {
-            debug(ex, "Exception on load operation");
-        }
-
-        return false;
-    }
-
-    @Override
-    public String invoke(String classname, String methodname) throws EvalException, UnresolvedReferenceException {
-        try {
-            synchronized (STOP_LOCK) {
-                userCodeRunning = true;
-            }
-
-            // Invoke executable entry point in loaded code
-            Class<?> klass = klasses.get(classname);
-            if (klass == null) {
-                debug("Invoke failure: no such class loaded %s\n", classname);
-
-                return "";
-            }
-
-            Method doitMethod;
-            try {
-                this.getClass().getModule().addReads(klass.getModule());
-                this.getClass().getModule().addExports(SPIResolutionException.class.getPackage()
-                        .getName(), klass.getModule());
-                doitMethod = klass.getDeclaredMethod(methodname, new Class<?>[0]);
-                doitMethod.setAccessible(true);
-
-                execThreadGroup = new ThreadGroup("JShell process local execution");
-
-                AtomicReference<InvocationTargetException> iteEx = new AtomicReference<>();
-                AtomicReference<IllegalAccessException> iaeEx = new AtomicReference<>();
-                AtomicReference<NoSuchMethodException> nmeEx = new AtomicReference<>();
-                AtomicReference<Boolean> stopped = new AtomicReference<>(false);
-
-                Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
-                    if (e instanceof InvocationTargetException) {
-                        if (e.getCause() instanceof ThreadDeath) {
-                            stopped.set(true);
-                        } else {
-                            iteEx.set((InvocationTargetException)e);
-                        }
-                    } else if (e instanceof IllegalAccessException) {
-                        iaeEx.set((IllegalAccessException)e);
-                    } else if (e instanceof NoSuchMethodException) {
-                        nmeEx.set((NoSuchMethodException)e);
-                    } else if (e instanceof ThreadDeath) {
-                        stopped.set(true);
-                    }
-                });
-
-                final Object[] res = new Object[1];
-                Thread snippetThread = new Thread(execThreadGroup, () -> {
-                    try {
-                        res[0] = doitMethod.invoke(null, new Object[0]);
-                    } catch (InvocationTargetException e) {
-                        if (e.getCause() instanceof ThreadDeath) {
-                            stopped.set(true);
-                        } else {
-                            iteEx.set(e);
-                        }
-                    } catch (IllegalAccessException e) {
-                        iaeEx.set(e);
-                    } catch (ThreadDeath e) {
-                        stopped.set(true);
-                    }
-                });
-
-                snippetThread.start();
-                Thread[] threadList = new Thread[execThreadGroup.activeCount()];
-                execThreadGroup.enumerate(threadList);
-                for (Thread thread : threadList) {
-                    if (thread != null)
-                        thread.join();
-                }
-
-                if (stopped.get()) {
-                    debug("Killed.");
-
-                    return "";
-                }
-
-                if (iteEx.get() != null) {
-                    throw iteEx.get();
-                } else if (nmeEx.get() != null) {
-                    throw nmeEx.get();
-                } else if (iaeEx.get() != null) {
-                    throw iaeEx.get();
-                }
-
-                return valueString(res[0]);
-            } catch (InvocationTargetException ex) {
-                Throwable cause = ex.getCause();
-                StackTraceElement[] elems = cause.getStackTrace();
-                if (cause instanceof SPIResolutionException) {
-                    int id = ((SPIResolutionException)cause).id();
-
-                    throw execEnv.createUnresolvedReferenceException(id, elems);
-                } else {
-                    throw execEnv.createEvalException(cause.getMessage() == null ?
-                            "<none>" : cause.getMessage(), cause.getClass().getName(), elems);
-                }
-            } catch (NoSuchMethodException | IllegalAccessException | InterruptedException ex) {
-                debug(ex, "Invoke failure");
-            }
-        } finally {
-            synchronized (STOP_LOCK) {
-                userCodeRunning = false;
-            }
-        }
-
-        return "";
-    }
-
-    @Override
-    @SuppressWarnings("deprecation")
-    public void stop() {
-        synchronized (STOP_LOCK) {
-            if (!userCodeRunning)
-                return;
-
-            if (execThreadGroup == null) {
-                debug("Process-local code snippets thread group is null. Aborting stop.");
-
-                return;
-            }
-
-            execThreadGroup.stop();
-        }
-    }
-
-    @Override
-    public String varValue(String classname, String varname) {
-        Class<?> klass = klasses.get(classname);
-        if (klass == null) {
-            debug("Var value failure: no such class loaded %s\n", classname);
-
-            return "";
-        }
-        try {
-            this.getClass().getModule().addReads(klass.getModule());
-            Field var = klass.getDeclaredField(varname);
-            var.setAccessible(true);
-            Object res = var.get(null);
-
-            return valueString(res);
-        } catch (Exception ex) {
-            debug("Var value failure: no such field %s.%s\n", classname, varname);
-        }
-
-        return "";
-    }
-
-    @Override
-    public boolean addToClasspath(String cp) {
-        // Append to the claspath
-        for (String path : cp.split(File.pathSeparator)) {
-            try {
-                loader.addURL(new File(path).toURI().toURL());
-            } catch (MalformedURLException e) {
-                throw new InternalError("Classpath addition failed: " + cp, e);
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean redefine(Collection<String> classes) {
-        return false;
-    }
-
-    @Override
-    public ClassStatus getClassStatus(String classname) {
-        if (!classBytes.containsKey(classname)) {
-            return ClassStatus.UNKNOWN;
-        } else if (!Arrays.equals(classBytes.get(classname), execEnv.getClassBytes(classname))) {
-            return ClassStatus.NOT_CURRENT;
-        } else {
-            return ClassStatus.CURRENT;
-        }
-    }
-
-    private void loadLocal(Collection<String> classes) throws ClassNotFoundException {
-        for (String className : classes) {
-            Class<?> klass = loader.loadClass(className);
-            klasses.put(className, klass);
-            classBytes.put(className, execEnv.getClassBytes(className));
-            klass.getDeclaredMethods();
-        }
-    }
-
-    private void debug(String format, Object... args) {
-        //debug(execEnv.state(), execEnv.userErr(), flags, format, args);
-    }
-
-    private void debug(Exception ex, String where) {
-        //debug(execEnv.state(), execEnv.userErr(), ex, where);
-    }
-
-    private static String valueString(Object value) {
-        if (value == null) {
-            return "null";
-        } else if (value instanceof String) {
-            return "\"" + (String)value + "\"";
-        } else if (value instanceof Character) {
-            return "'" + value + "'";
-        } else {
-            return value.toString();
-        }
-    }
-}
--- a/langtools/test/jdk/jshell/UserExecutionControlTest.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/jdk/jshell/UserExecutionControlTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -23,13 +23,14 @@
 
 /*
  * @test
- * @bug 8156101
+ * @bug 8156101 8159935 8159122
  * @summary Tests for ExecutionControl SPI
- * @build KullaTesting LocalExecutionControl ExecutionControlTestBase
+ * @build KullaTesting ExecutionControlTestBase
  * @run testng UserExecutionControlTest
  */
 
 
+import jdk.jshell.execution.LocalExecutionControl;
 import org.testng.annotations.Test;
 import static org.testng.Assert.assertEquals;
 import org.testng.annotations.BeforeMethod;
@@ -40,7 +41,7 @@
     @BeforeMethod
     @Override
     public void setUp() {
-        setUp(new LocalExecutionControl());
+        setUp(builder -> builder.executionEngine(LocalExecutionControl.create()));
     }
 
     public void verifyLocal() throws ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/UserJDIUserRemoteTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @bug 8160128 8159935
+ * @summary Tests for Aux channel, custom remote agents, custom JDI implementations.
+ * @build KullaTesting ExecutionControlTestBase
+ * @run testng UserJDIUserRemoteTest
+ */
+import java.io.ByteArrayOutputStream;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import jdk.jshell.Snippet;
+import static jdk.jshell.Snippet.Status.OVERWRITTEN;
+import static jdk.jshell.Snippet.Status.VALID;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.net.ServerSocket;
+import java.util.ArrayList;
+import java.util.List;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VirtualMachine;
+import jdk.jshell.VarSnippet;
+import jdk.jshell.execution.DirectExecutionControl;
+import jdk.jshell.execution.JDIExecutionControl;
+import jdk.jshell.execution.JDIInitiator;
+import jdk.jshell.execution.Util;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.Socket;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+import jdk.jshell.spi.ExecutionControl;
+import jdk.jshell.spi.ExecutionControl.ExecutionControlException;
+import jdk.jshell.spi.ExecutionEnv;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+import static jdk.jshell.execution.Util.forwardExecutionControlAndIO;
+import static jdk.jshell.execution.Util.remoteInput;
+
+@Test
+public class UserJDIUserRemoteTest extends ExecutionControlTestBase {
+
+    ExecutionControl currentEC;
+    ByteArrayOutputStream auxStream;
+
+    @BeforeMethod
+    @Override
+    public void setUp() {
+        auxStream = new ByteArrayOutputStream();
+        setUp(builder -> builder.executionEngine(MyExecutionControl.create(this)));
+    }
+
+    public void testVarValue() {
+        VarSnippet dv = varKey(assertEval("double aDouble = 1.5;"));
+        String vd = getState().varValue(dv);
+        assertEquals(vd, "1.5");
+        assertEquals(auxStream.toString(), "aDouble");
+    }
+
+    public void testExtension() throws ExecutionControlException {
+        assertEval("42;");
+        Object res = currentEC.extensionCommand("FROG", "test");
+        assertEquals(res, "ribbit");
+    }
+
+    public void testRedefine() {
+        Snippet vx = varKey(assertEval("int x;"));
+        Snippet mu = methodKey(assertEval("int mu() { return x * 4; }"));
+        Snippet c = classKey(assertEval("class C { String v() { return \"#\" + mu(); } }"));
+        assertEval("C c0  = new C();");
+        assertEval("c0.v();", "\"#0\"");
+        assertEval("int x = 10;", "10",
+                ste(MAIN_SNIPPET, VALID, VALID, false, null),
+                ste(vx, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
+        assertEval("c0.v();", "\"#40\"");
+        assertEval("C c = new C();");
+        assertEval("c.v();", "\"#40\"");
+        assertEval("int mu() { return x * 3; }",
+                ste(MAIN_SNIPPET, VALID, VALID, false, null),
+                ste(mu, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
+        assertEval("c.v();", "\"#30\"");
+        assertEval("class C { String v() { return \"@\" + mu(); } }",
+                ste(MAIN_SNIPPET, VALID, VALID, false, null),
+                ste(c, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
+        assertEval("c0.v();", "\"@30\"");
+        assertEval("c = new C();");
+        assertEval("c.v();", "\"@30\"");
+        assertActiveKeys();
+    }
+}
+
+class MyExecutionControl extends JDIExecutionControl {
+
+    private static final String REMOTE_AGENT = MyRemoteExecutionControl.class.getName();
+
+    private VirtualMachine vm;
+    private Process process;
+
+    /**
+     * Creates an ExecutionControl instance based on a JDI
+     * {@code LaunchingConnector}.
+     *
+     * @return the generator
+     */
+    public static ExecutionControl.Generator create(UserJDIUserRemoteTest test) {
+        return env -> make(env, test);
+    }
+
+    /**
+     * Creates an ExecutionControl instance based on a JDI
+     * {@code ListeningConnector} or {@code LaunchingConnector}.
+     *
+     * Initialize JDI and use it to launch the remote JVM. Set-up a socket for
+     * commands and results. This socket also transports the user
+     * input/output/error.
+     *
+     * @param env the context passed by
+         * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }
+     * @return the channel
+     * @throws IOException if there are errors in set-up
+     */
+    static MyExecutionControl make(ExecutionEnv env, UserJDIUserRemoteTest test) throws IOException {
+        try (final ServerSocket listener = new ServerSocket(0)) {
+            // timeout after 60 seconds
+            listener.setSoTimeout(60000);
+            int port = listener.getLocalPort();
+
+            // Set-up the JDI connection
+            List<String> opts = new ArrayList<>(env.extraRemoteVMOptions());
+            opts.add("-classpath");
+            opts.add(System.getProperty("java.class.path")
+                    + System.getProperty("path.separator")
+                    + System.getProperty("user.dir"));
+            JDIInitiator jdii = new JDIInitiator(port,
+                    opts, REMOTE_AGENT, true);
+            VirtualMachine vm = jdii.vm();
+            Process process = jdii.process();
+
+            List<Consumer<String>> deathListeners = new ArrayList<>();
+            deathListeners.add(s -> env.closeDown());
+            Util.detectJDIExitEvent(vm, s -> {
+                for (Consumer<String> h : deathListeners) {
+                    h.accept(s);
+                }
+            });
+
+            // Set-up the commands/reslts on the socket.  Piggy-back snippet
+            // output.
+            Socket socket = listener.accept();
+            // out before in -- match remote creation so we don't hang
+            ObjectOutput cmdout = new ObjectOutputStream(socket.getOutputStream());
+            Map<String, OutputStream> io = new HashMap<>();
+            io.put("out", env.userOut());
+            io.put("err", env.userErr());
+            io.put("aux", test.auxStream);
+            ObjectInput cmdin = remoteInput(socket.getInputStream(), io);
+            MyExecutionControl myec = new MyExecutionControl(cmdout, cmdin, vm, process, deathListeners);
+            test.currentEC = myec;
+            return myec;
+        }
+    }
+
+    /**
+     * Create an instance.
+     *
+     * @param out the output for commands
+     * @param in the input for responses
+     */
+    private MyExecutionControl(ObjectOutput out, ObjectInput in,
+            VirtualMachine vm, Process process,
+            List<Consumer<String>> deathListeners) {
+        super(out, in);
+        this.vm = vm;
+        this.process = process;
+        deathListeners.add(s -> disposeVM());
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        disposeVM();
+    }
+
+    private synchronized void disposeVM() {
+        try {
+            if (vm != null) {
+                vm.dispose(); // This could NPE, so it is caught below
+                vm = null;
+            }
+        } catch (VMDisconnectedException ex) {
+            // Ignore if already closed
+        } catch (Throwable e) {
+            fail("disposeVM threw: " + e);
+        } finally {
+            if (process != null) {
+                process.destroy();
+                process = null;
+            }
+        }
+    }
+
+    @Override
+    protected synchronized VirtualMachine vm() throws EngineTerminationException {
+        if (vm == null) {
+            throw new EngineTerminationException("VM closed");
+        } else {
+            return vm;
+        }
+    }
+
+}
+
+class MyRemoteExecutionControl extends DirectExecutionControl implements ExecutionControl {
+
+    static PrintStream auxPrint;
+
+    /**
+     * Launch the agent, connecting to the JShell-core over the socket specified
+     * in the command-line argument.
+     *
+     * @param args standard command-line arguments, expectation is the socket
+     * number is the only argument
+     * @throws Exception any unexpected exception
+     */
+    public static void main(String[] args) throws Exception {
+        try {
+            String loopBack = null;
+            Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
+            InputStream inStream = socket.getInputStream();
+            OutputStream outStream = socket.getOutputStream();
+            Map<String, Consumer<OutputStream>> chans = new HashMap<>();
+            chans.put("out", st -> System.setOut(new PrintStream(st, true)));
+            chans.put("err", st -> System.setErr(new PrintStream(st, true)));
+            chans.put("aux", st -> { auxPrint = new PrintStream(st, true); });
+            forwardExecutionControlAndIO(new MyRemoteExecutionControl(), inStream, outStream, chans);
+        } catch (Throwable ex) {
+            throw ex;
+        }
+    }
+
+    @Override
+    public String varValue(String className, String varName)
+            throws RunException, EngineTerminationException, InternalException {
+        auxPrint.print(varName);
+        return super.varValue(className, varName);
+    }
+
+    @Override
+    public Object extensionCommand(String className, Object arg)
+            throws RunException, EngineTerminationException, InternalException {
+        if (!arg.equals("test")) {
+            throw new InternalException("expected extensionCommand arg to be 'test' got: " + arg);
+        }
+        return "ribbit";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8161985/T8161985a.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,28 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8161985
+ * @summary Spurious override of Object.getClass leads to NPE
+ * @compile/fail/ref=T8161985a.out -XDrawDiagnostics T8161985a.java
+ */
+
+class T8161985 {
+    public static void main(String [] arg) {
+        T8161985 t = new T8161985();
+        t.getClass();
+
+    }
+    public void getClass() {
+        Fred1 f = new Fred1();
+        System.out.println( "fred classname: " + f.getClassName());
+    }
+
+
+    abstract class Fred {
+        public String getClassName() {
+            return this.getClass().getSimpleName();
+        }
+    }
+
+    class Fred1 extends Fred {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8161985/T8161985a.out	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,2 @@
+T8161985a.java:14:17: compiler.err.override.meth: (compiler.misc.cant.override: getClass(), T8161985, getClass(), java.lang.Object), final
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8161985/T8161985b.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8161985
+ * @summary Spurious override of Object.getClass leads to NPE
+ * @compile/fail/ref=T8161985b.out -XDrawDiagnostics T8161985b.java
+ */
+
+class T8161985b {
+   public String getClass() { return ""; }
+
+   void test() {
+      this.getClass().getSimpleName();
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8161985/T8161985b.out	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,3 @@
+T8161985b.java:9:18: compiler.err.override.meth: (compiler.misc.cant.override: getClass(), T8161985b, getClass(), java.lang.Object), final
+T8161985b.java:12:22: compiler.err.cant.resolve.location.args: kindname.method, getSimpleName, , , (compiler.misc.location: kindname.class, java.lang.String, null)
+2 errors
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234a.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234a.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,8 +3,8 @@
  * @bug     6722234
  * @summary javac diagnostics need better integration with the type-system
  * @author  mcimadamore
- * @compile/fail/ref=T6722234a_1.out -XDrawDiagnostics -XDdiags=disambiguateTvars T6722234a.java
- * @compile/fail/ref=T6722234a_2.out -XDrawDiagnostics -XDdiags=disambiguateTvars,where T6722234a.java
+ * @compile/fail/ref=T6722234a_1.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars T6722234a.java
+ * @compile/fail/ref=T6722234a_2.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars,where T6722234a.java
  */
 
 class T6722234a<T extends String> {
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234b.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234b.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,8 +3,8 @@
  * @bug     6722234 8078024
  * @summary javac diagnostics need better integration with the type-system
  * @author  mcimadamore
- * @compile/fail/ref=T6722234b_1.out -XDrawDiagnostics -XDdiags=simpleNames T6722234b.java
- * @compile/fail/ref=T6722234b_2.out -XDrawDiagnostics -XDdiags=simpleNames,where T6722234b.java
+ * @compile/fail/ref=T6722234b_1.out -XDrawDiagnostics -diags:formatterOptions=simpleNames T6722234b.java
+ * @compile/fail/ref=T6722234b_2.out -XDrawDiagnostics -diags:formatterOptions=simpleNames,where T6722234b.java
  */
 
 import java.util.*;
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234c.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234c.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,7 +3,7 @@
  * @bug     6722234
  * @summary javac diagnostics need better integration with the type-system
  * @author  mcimadamore
- * @compile/fail/ref=T6722234c.out -XDrawDiagnostics -XDdiags=simpleNames T6722234c.java
+ * @compile/fail/ref=T6722234c.out -XDrawDiagnostics -diags:formatterOptions=simpleNames T6722234c.java
  */
 
 class T6722234c {
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234d.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234d.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,8 +3,8 @@
  * @bug     6722234 8078024
  * @summary javac diagnostics need better integration with the type-system
  * @author  mcimadamore
- * @compile/fail/ref=T6722234d_1.out -XDrawDiagnostics -XDdiags=where T6722234d.java
- * @compile/fail/ref=T6722234d_2.out -XDrawDiagnostics -XDdiags=where,simpleNames T6722234d.java
+ * @compile/fail/ref=T6722234d_1.out -XDrawDiagnostics -diags:formatterOptions=where T6722234d.java
+ * @compile/fail/ref=T6722234d_2.out -XDrawDiagnostics -diags:formatterOptions=where,simpleNames T6722234d.java
  */
 
 class T6722234d {
--- a/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,8 +59,8 @@
 
     enum CaretKind {
         DEFAULT("", ""),
-        SHOW("showCaret","true"),
-        HIDE("showCaret","false");
+        SHOW("diags.showCaret","true"),
+        HIDE("diags.showCaret","false");
 
         String key;
         String value;
@@ -81,8 +81,8 @@
 
     enum SourceLineKind {
         DEFAULT("", ""),
-        AFTER_SUMMARY("sourcePosition", "top"),
-        BOTTOM("sourcePosition", "bottom");
+        AFTER_SUMMARY("diags.sourcePosition", "top"),
+        BOTTOM("diags.sourcePosition", "bottom");
 
         String key;
         String value;
@@ -110,9 +110,9 @@
 
         void init(Options opts) {
             if (this != DEFAULT) {
-                String flags = opts.get("diags");
+                String flags = opts.get("diags.formatterOptions");
                 flags = flags == null ? flag : flags + "," + flag;
-                opts.put("diags", flags);
+                opts.put("diags.formatterOptions", flags);
             }
         }
 
@@ -136,9 +136,9 @@
 
         void init(Options opts) {
             if (this != DEFAULT) {
-                String flags = opts.get("diags");
+                String flags = opts.get("diags.formatterOptions");
                 flags = flags == null ? flag : flags + "," + flag;
-                opts.put("diags", flags);
+                opts.put("diags.formatterOptions", flags);
             }
         }
 
@@ -243,11 +243,11 @@
     }
 
     enum MultilinePolicy {
-        ENABLED(0, "multilinePolicy", "enabled"),
-        DISABLED(1, "multilinePolicy", "disabled"),
-        LIMIT_LENGTH(2, "multilinePolicy", "limit:1:*"),
-        LIMIT_DEPTH(3, "multilinePolicy", "limit:*:1"),
-        LIMIT_BOTH(4, "multilinePolicy", "limit:1:1");
+        ENABLED(0, "diags.multilinePolicy", "enabled"),
+        DISABLED(1, "diags.multilinePolicy", "disabled"),
+        LIMIT_LENGTH(2, "diags.multilinePolicy", "limit:1:*"),
+        LIMIT_DEPTH(3, "diags.multilinePolicy", "limit:*:1"),
+        LIMIT_BOTH(4, "diags.multilinePolicy", "limit:1:1");
 
         String name;
         String value;
@@ -371,7 +371,7 @@
         indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
         indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0";
         indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
-        options.put("diagsIndentation", indentString);
+        options.put("diags.indent", indentString);
         MyLog log = new MyLog(ctx);
         JavacMessages messages = JavacMessages.instance(ctx);
         messages.add(locale -> ResourceBundle.getBundle("tester", locale));
--- a/langtools/test/tools/javac/Diagnostics/6862608/T6862608a.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/6862608/T6862608a.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,7 +3,7 @@
  * @bug     6862608
  * @summary rich diagnostic sometimes contain wrong type variable numbering
  * @author  mcimadamore
- * @compile/fail/ref=T6862608a.out -XDrawDiagnostics -XDdiags=disambiguateTvars,where T6862608a.java
+ * @compile/fail/ref=T6862608a.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars,where T6862608a.java
  */
 
 
--- a/langtools/test/tools/javac/Diagnostics/6862608/T6862608b.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/6862608/T6862608b.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,7 +3,7 @@
  * @bug     6862608
  * @summary rich diagnostic sometimes contain wrong type variable numbering
  * @author  mcimadamore
- * @compile/fail/ref=T6862608b.out -XDrawDiagnostics -XDdiags=disambiguateTvars,where T6862608b.java
+ * @compile/fail/ref=T6862608b.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars,where T6862608b.java
  */
 
 class T66862608b<T extends String, S> {
--- a/langtools/test/tools/javac/Diagnostics/7010608/Test.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/7010608/Test.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,9 +46,9 @@
         try {
             test(Arrays.<String>asList(),
                     "myfo://test:1: error: cannot find symbol");
-            test(Arrays.asList("-XDdiagsFormat=OLD"),
+            test(Arrays.asList("-diags:layout=OLD"),
                     "myfo://test:1: cannot find symbol");
-            test(Arrays.asList("-XDoldDiags"),
+            test(Arrays.asList("-diags:legacy"),
                     "myfo://test:1: cannot find symbol");
         } finally {
             Locale.setDefault(prev);
--- a/langtools/test/tools/javac/Diagnostics/8010387/T8010387.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/Diagnostics/8010387/T8010387.java	Wed Jul 05 22:00:06 2017 +0200
@@ -2,7 +2,7 @@
  * @test /nodynamiccopyright/
  * @bug     8010387
  * @summary rich diagnostic sometimes contain wrong type variable numbering
- * @compile/fail/ref=T8010387.out -XDrawDiagnostics -XDdiags=disambiguateTvars,where T8010387.java
+ * @compile/fail/ref=T8010387.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars,where T8010387.java
  */
 abstract class T8010387<X> {
 
--- a/langtools/test/tools/javac/InterfaceMemberClassModifiers.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/InterfaceMemberClassModifiers.java	Wed Jul 05 22:00:06 2017 +0200
@@ -4,7 +4,7 @@
  * @summary Verify that invalid access modifiers on interface members don't cause crash.
  * @author maddox
  *
- * @compile/fail/ref=InterfaceMemberClassModifiers.out -XDdiags=%b:%l:%_%m InterfaceMemberClassModifiers.java
+ * @compile/fail/ref=InterfaceMemberClassModifiers.out -diags:layout=%b:%l:%_%m InterfaceMemberClassModifiers.java
  */
 
 public interface InterfaceMemberClassModifiers {
--- a/langtools/test/tools/javac/T5003235/T5003235a.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/T5003235/T5003235a.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,7 +3,7 @@
  * @bug     5003235
  * @summary Private inner class accessible from subclasses
  * @author  Peter von der Ah\u00e9
- * @compile/fail/ref=T5003235a.out -XDdiags=%b:%l:%_%m T5003235a.java
+ * @compile/fail/ref=T5003235a.out -diags:layout=%b:%l:%_%m T5003235a.java
  */
 
 class Super {
--- a/langtools/test/tools/javac/T5003235/T5003235b.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/T5003235/T5003235b.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,7 +3,7 @@
  * @bug     5003235
  * @summary Accessibility of private inner class
  * @author  Peter von der Ah\u00e9
- * @compile/fail/ref=T5003235b.out -XDdiags=%b:%l:%_%m T5003235b.java
+ * @compile/fail/ref=T5003235b.out -diags:layout=%b:%l:%_%m T5003235b.java
  */
 
 class Outer {
--- a/langtools/test/tools/javac/T6214885.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/T6214885.java	Wed Jul 05 22:00:06 2017 +0200
@@ -2,8 +2,8 @@
  * @test  /nodynamiccopyright/
  * @bug 6214885
  * @summary This test exercises features provided by the new internal Diagnostics API
- * @compile/fail/ref=T6214885a.out -XDdiags=%b:%l%_%t%m|%p%m T6214885.java
- * @compile/fail/ref=T6214885b.out -XDdiags=%b:%l:%c%_%t%m|%p%m T6214885.java
+ * @compile/fail/ref=T6214885a.out -diags:layout=%b:%l%_%t%m|%p%m T6214885.java
+ * @compile/fail/ref=T6214885b.out -diags:layout=%b:%l:%c%_%t%m|%p%m T6214885.java
  */
 class T6214885
 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8161383/LookingForOperatorSymbolsAtWrongPlaceTest.java	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,18 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8161383
+ * @summary javac is looking for operator symbols at the wrong place
+ * @compile LookingForOperatorSymbolsAtWrongPlaceTest.java
+ */
+
+public class LookingForOperatorSymbolsAtWrongPlaceTest {
+    class Base {
+        protected int i = 1;
+    }
+
+    class Sub extends Base {
+        void func(){
+            Sub.super.i += 10;
+        }
+    }
+}
--- a/langtools/test/tools/javac/api/6731573/T6731573.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/api/6731573/T6731573.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -62,8 +62,8 @@
 
     enum SourceLine {
         STANDARD(null),
-        ENABLED("-XDshowSource=true"),
-        DISABLED("-XDshowSource=false");
+        ENABLED("-diags:showSource=true"),
+        DISABLED("-diags:showSource=false");
 
         String optValue;
 
--- a/langtools/test/tools/javac/diags/CheckResourceKeys.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/diags/CheckResourceKeys.java	Wed Jul 05 22:00:06 2017 +0200
@@ -263,6 +263,9 @@
                 // ignore shouldstop flag names
                 if (cs.startsWith("shouldstop."))
                     continue;
+                // ignore diagsformat flag names
+                if (cs.startsWith("diags."))
+                    continue;
                 // explicit known exceptions
                 if (noResourceRequired.contains(cs))
                     continue;
--- a/langtools/test/tools/javac/diags/examples/WhereCaptured.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/WhereCaptured.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
 // key: compiler.err.cant.apply.symbol
 // key: compiler.misc.incompatible.eq.bounds
 // key: compiler.misc.captured.type
-// options: -XDdiags=where,simpleNames
+// options: -diags:formatterOptions=where,simpleNames
 // run: simple
 
 import java.util.*;
--- a/langtools/test/tools/javac/diags/examples/WhereCaptured1.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/WhereCaptured1.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
 // key: compiler.misc.incompatible.eq.bounds
 // key: compiler.misc.captured.type
 // key: compiler.misc.type.null
-// options: -XDdiags=where,simpleNames
+// options: -diags:formatterOptions=where,simpleNames
 // run: simple
 
 import java.util.*;
--- a/langtools/test/tools/javac/diags/examples/WhereFreshTvar.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/WhereFreshTvar.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
 // key: compiler.misc.where.description.typevar
 // key: compiler.err.prob.found.req
 // key: compiler.misc.inconvertible.types
-// options: -XDdiags=where,simpleNames
+// options: -diags:formatterOptions=where,simpleNames
 // run: simple
 
 import java.util.*;
--- a/langtools/test/tools/javac/diags/examples/WhereIntersection.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/WhereIntersection.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
 // key: compiler.misc.where.description.intersection.1
 // key: compiler.misc.where.intersection
 // key: compiler.err.prob.found.req
-// options: -XDdiags=where
+// options: -diags:formatterOptions=where
 // run: simple
 
 class WhereIntersection {
--- a/langtools/test/tools/javac/diags/examples/WhereIntersection2.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/WhereIntersection2.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
 // key: compiler.misc.where.description.intersection
 // key: compiler.misc.where.intersection
 // key: compiler.err.prob.found.req
-// options: -XDdiags=where
+// options: -diags:formatterOptions=where
 // run: simple
 
 class WhereIntersection2 {
--- a/langtools/test/tools/javac/diags/examples/WhereTypeVar.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/WhereTypeVar.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@
 // key: compiler.err.cant.apply.symbol
 // key: compiler.misc.no.conforming.assignment.exists
 // key: compiler.misc.inconvertible.types
-// options: -XDdiags=where,disambiguateTvars
+// options: -diags:formatterOptions=where,disambiguateTvars
 // run: simple
 
 class WhereTypeVar<T extends String> {
--- a/langtools/test/tools/javac/diags/examples/WhereTypeVar2.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/WhereTypeVar2.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
 // key: compiler.misc.where.description.typevar
 // key: compiler.misc.where.typevar
 // key: compiler.err.prob.found.req
-// options: -XDdiags=where
+// options: -diags:formatterOptions=where
 // run: simple
 
 class WhereTypeVar2 {
--- a/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.java	Wed Jul 05 22:00:06 2017 +0200
@@ -5,7 +5,7 @@
  * class is no longer available during a subsequent compilation.
  * @author maddox
  * @build impl
- * @compile/fail/ref=MissingSuperRecovery.out -XDdiags=%b:%l:%_%m MissingSuperRecovery.java
+ * @compile/fail/ref=MissingSuperRecovery.out -diags:layout=%b:%l:%_%m MissingSuperRecovery.java
  */
 
 // Requires "golden" class file 'impl.class', which contains
--- a/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess2.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess2.java	Wed Jul 05 22:00:06 2017 +0200
@@ -4,7 +4,7 @@
  * @summary Verify correct implementation of JLS2e 6.6.2.1
  * @author maddox
  *
- * @compile/fail/ref=ProtectedMemberAccess2.out -XDdiags=-simpleNames -XDdiagsFormat=%b:%l:%_%m ProtectedMemberAccess2.java
+ * @compile/fail/ref=ProtectedMemberAccess2.out -diags:formatterOptions=-simpleNames;layout=%b:%l:%_%m ProtectedMemberAccess2.java
  */
 
 // 71 errors expected.
--- a/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess3.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess3.java	Wed Jul 05 22:00:06 2017 +0200
@@ -4,7 +4,7 @@
  * @summary Verify correct implementation of JLS2e 6.6.2.1
  * @author maddox
  *
- * @compile/fail/ref=ProtectedMemberAccess3.out -XDdiags=-simpleNames -XDdiagsFormat=%b:%l:%_%m ProtectedMemberAccess3.java
+ * @compile/fail/ref=ProtectedMemberAccess3.out -diags:formatterOptions=-simpleNames;layout=%b:%l:%_%m ProtectedMemberAccess3.java
  */
 
 // 46 errors expected.
--- a/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess4.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess4.java	Wed Jul 05 22:00:06 2017 +0200
@@ -4,7 +4,7 @@
  * @summary Verify correct implementation of JLS2e 6.6.2.1
  * @author maddox
  *
- * @compile/fail/ref=ProtectedMemberAccess4.out -XDdiags=-simpleNames -XDdiagsFormat=%b:%l:%_%m ProtectedMemberAccess4.java
+ * @compile/fail/ref=ProtectedMemberAccess4.out -diags:formatterOptions=-simpleNames;layout=%b:%l:%_%m ProtectedMemberAccess4.java
  */
 
 // 33 errors expected.
--- a/langtools/test/tools/javac/unicode/UnicodeNewline.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/langtools/test/tools/javac/unicode/UnicodeNewline.java	Wed Jul 05 22:00:06 2017 +0200
@@ -3,7 +3,7 @@
  * @bug 4739428 4785453
  * @summary when \u000a is used, diagnostics are reported on the wrong line.
  *
- * @compile/fail/ref=UnicodeNewline.out -XDdiags=%b:%l:%_%m UnicodeNewline.java
+ * @compile/fail/ref=UnicodeNewline.out -diags:layout=%b:%l:%_%m UnicodeNewline.java
  */
 
 class UnicodeNewline {
--- a/nashorn/.hgtags	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/.hgtags	Wed Jul 05 22:00:06 2017 +0200
@@ -361,3 +361,4 @@
 a32d419d73fe881a935b567c57dab9bfe3ed5f92 jdk-9+125
 ee90c69a18409533df8f7b602044bf966a28381a jdk-9+126
 ff07be6106fa56b72c163244f45a3ecb4c995564 jdk-9+127
+5a189c5b396c353786343b590f6c19a5d929f01d jdk-9+128
--- a/nashorn/make/build-nasgen.xml	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/make/build-nasgen.xml	Wed Jul 05 22:00:06 2017 +0200
@@ -43,14 +43,14 @@
         </java>
     </target>
 
-    <target name="run-nasgen-eclipse">
+    <target name="run-nasgen-eclipse" depends="load-properties">
         <mkdir dir="${basedir}/build/eclipse/.nasgentmp"/>
 
         <java classname="jdk.nashorn.internal.tools.nasgen.Main" fork="true" failonerror="true">
             <classpath>
                 <pathelement location="${basedir}/buildtools/nasgen/dist/nasgen.jar"/>
             </classpath>
-            <jvmarg value="-Xbootclasspath/p:${basedir}/build/eclipse"/>
+            <jvmarg line="${nasgen.module.imports}"/>
             <arg value="${basedir}/build/eclipse"/>
             <arg value="jdk.nashorn.internal.objects"/>
             <arg value="${basedir}/build/eclipse/.nasgentmp"/>
--- a/nashorn/make/build.xml	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/make/build.xml	Wed Jul 05 22:00:06 2017 +0200
@@ -27,11 +27,14 @@
   <import file="build-nasgen.xml"/>
   <import file="code_coverage.xml"/>
 
-  <target name="init-conditions">
+  <target name="load-properties">
     <!-- loading locally defined resources and properties. NB they owerwrite default ones defined later -->
     <property file="${user.home}/.nashorn.project.local.properties"/>
 
     <loadproperties srcFile="make/project.properties"/>
+  </target>
+
+  <target name="init-conditions" depends="load-properties">
     <path id="nashorn.jar.path">
          <pathelement location="${nashorn.jar}"/>
     </path>
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java	Wed Jul 05 22:00:06 2017 +0200
@@ -108,15 +108,19 @@
      * language's objects to Java interfaces and classes by generating adapters
      * for them.
      * <p>
-     * The type of the invocation is {@code targetType(sourceType)}, while the
-     * type of the guard is {@code boolean(sourceType)}. You are allowed to
+     * The type of the invocation is <tt>(sourceType)&rarr;targetType</tt>, while the
+     * type of the guard is <tt>(sourceType)&rarr;boolean</tt>. You are allowed to
      * return unconditional invocations (with no guard) if the source type is
      * specific to your runtime and your runtime only.
-     * <p>Note that this method will never be invoked for type conversions
-     * allowed by the JLS 5.3 "Method Invocation Conversion", see
-     * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for
-     * details. An implementation can assume it is never requested to produce a
-     * converter for these conversions.
+     * <p>Note that this method will never be invoked for
+     * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method
+     * invocation conversions} as those can be automatically applied by
+     * {@link java.lang.invoke.MethodHandle#asType(MethodType)}.
+     * An implementation can assume it is never requested to produce a
+     * converter for those conversions. If a language runtime needs to customize
+     * method invocation conversions, it should
+     * {@link jdk.dynalink.DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy)
+     * set an autoconversion strategy in the dynamic linker factory} instead.
      * <p>Dynalink is at liberty to either cache some of the returned converters
      * or to repeatedly request the converter factory to create the same
      * conversion.
@@ -127,6 +131,9 @@
      * on whose behalf a type converter is requested. When a converter is
      * requested as part of linking an {@code invokedynamic} instruction the
      * supplier will return the lookup passed to the bootstrap method, otherwise
+     * if the method is invoked from within a
+     * {@link LinkerServices#getWithLookup(Supplier, jdk.dynalink.SecureLookupSupplier)}
+     * it will delegate to the secure lookup supplier. In any other case,
      * it will return the public lookup. A typical case where the lookup might
      * be needed is when the converter creates a Java adapter class on the fly
      * (e.g. to convert some object from the dynamic language into a Java
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/package-info.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/package-info.java	Wed Jul 05 22:00:06 2017 +0200
@@ -96,10 +96,8 @@
  * language-specific manner if no other linker managed to handle the operation.)
  * </p><p>
  * A language runtime that wishes to make at least some of its linkers available
- * to other language runtimes for interoperability will need to declare the
- * class names of those linkers in
- * {@code /META-INF/services/jdk.dynalink.linker.GuardingDynamicLinker} file in
- * its distribution (typically, JAR file).
+ * to other language runtimes for interoperability will need to use a
+ * {@link jdk.dynalink.linker.GuardingDynamicLinkerExporter}.
  * </p><p>
  * Most language runtimes will be able to implement their own linking logic by
  * implementing {@link jdk.dynalink.linker.TypeBasedGuardingDynamicLinker}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java	Wed Jul 05 22:00:06 2017 +0200
@@ -138,7 +138,7 @@
      * Determines whether one type can be converted to another type using a method invocation conversion, as per JLS 5.3
      * "Method Invocation Conversion". This is basically all conversions allowed by subtyping (see
      * {@link #isSubtype(Class, Class)}) as well as boxing conversion (JLS 5.1.7) optionally followed by widening
-     * reference conversion and unboxing conversion (JLS 5.1.8) optionally followed by widening primitive conversion.
+     * reference conversion, and unboxing conversion (JLS 5.1.8) optionally followed by widening primitive conversion.
      *
      * @param sourceType the type being converted from (call site type for parameter types, method type for return types)
      * @param targetType the parameter type being converted to (method type for parameter types, call site type for return types)
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java	Wed Jul 05 22:00:06 2017 +0200
@@ -90,9 +90,10 @@
 
 /**
  * A relinkable call site that implements monomorphic inline caching strategy,
- * only being linked to a single {@link GuardedInvocation}. If that invocation
- * is invalidated, it will throw it away and ask its associated
- * {@link DynamicLinker} to relink it.
+ * only being linked to a single {@link GuardedInvocation} at any given time.
+ * If the guard of that single invocation fails, or it has an invalidated
+ * switch point, or its invalidating exception triggered, then the call site
+ * will throw it away and ask its associated {@link DynamicLinker} to relink it.
  */
 public class SimpleRelinkableCallSite extends AbstractRelinkableCallSite {
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Wed Jul 05 22:00:06 2017 +0200
@@ -1329,30 +1329,31 @@
             return ScriptRuntime.UNDEFINED;
         }
 
-        final Object start = args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED;
-        final Object deleteCount = args.length > 1 ? args[1] : ScriptRuntime.UNDEFINED;
-
-        Object[] items;
-
-        if (args.length > 2) {
-            items = new Object[args.length - 2];
-            System.arraycopy(args, 2, items, 0, items.length);
-        } else {
-            items = ScriptRuntime.EMPTY_ARRAY;
-        }
-
-        final ScriptObject sobj                = (ScriptObject)obj;
-        final long         len                 = JSType.toUint32(sobj.getLength());
-        final long         relativeStart       = JSType.toLong(start);
+        final ScriptObject sobj          = (ScriptObject)obj;
+        final long         len           = JSType.toUint32(sobj.getLength());
+        final long         relativeStart = JSType.toLong(args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED);
 
         final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
-        final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart);
+        final long actualDeleteCount;
+        Object[] items = ScriptRuntime.EMPTY_ARRAY;
+
+        if (args.length == 0) {
+            actualDeleteCount = 0;
+        } else if (args.length == 1) {
+            actualDeleteCount = len - actualStart;
+        } else {
+            actualDeleteCount = Math.min(Math.max(JSType.toLong(args[1]), 0), len - actualStart);
+            if (args.length > 2) {
+                items = new Object[args.length - 2];
+                System.arraycopy(args, 2, items, 0, items.length);
+            }
+        }
 
         NativeArray returnValue;
 
         if (actualStart <= Integer.MAX_VALUE && actualDeleteCount <= Integer.MAX_VALUE && bulkable(sobj)) {
             try {
-                returnValue =  new NativeArray(sobj.getArray().fastSplice((int)actualStart, (int)actualDeleteCount, items.length));
+                returnValue = new NativeArray(sobj.getArray().fastSplice((int)actualStart, (int)actualDeleteCount, items.length));
 
                 // Since this is a dense bulkable array we can use faster defineOwnProperty to copy new elements
                 int k = (int) actualStart;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java	Wed Jul 05 22:00:06 2017 +0200
@@ -127,7 +127,7 @@
     // Fold an accessor getter into the method handle of a user accessor property.
     private MethodHandle insertAccessorsGetter(final UserAccessorProperty uap, final LinkRequest request, final MethodHandle mh) {
         MethodHandle superGetter = uap.getAccessorsGetter();
-        if (isInherited()) {
+        if (!isSelf()) {
             superGetter = ScriptObject.addProtoFilter(superGetter, getProtoChainLength());
         }
         if (request != null && !(request.getReceiver() instanceof ScriptObject)) {
@@ -183,11 +183,12 @@
     }
 
     /**
-     * Check if the property found was inherited, i.e. not directly in the self
-     * @return true if inherited property
+     * Check if the property found was inherited from a prototype and it is an ordinary
+     * property (one that has no accessor function).
+     * @return true if the found property is an inherited ordinary property
      */
-    public boolean isInherited() {
-        return self != prototype;
+    public boolean isInheritedOrdinaryProperty() {
+        return !isSelf() && !getProperty().isAccessorProperty();
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Jul 05 22:00:06 2017 +0200
@@ -796,7 +796,7 @@
      * @param start the object on which the lookup was originally initiated
      * @return FindPropertyData or null if not found.
      */
-    protected FindProperty findProperty(final Object key, final boolean deep, boolean isScope, final ScriptObject start) {
+    protected FindProperty findProperty(final Object key, final boolean deep, final boolean isScope, final ScriptObject start) {
 
         final PropertyMap selfMap  = getMap();
         final Property    property = selfMap.findProperty(key);
@@ -1108,7 +1108,7 @@
      *
      * @return value of property as a MethodHandle or null.
      */
-    protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
+    protected static MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
         return getCallMethodHandle(find.getObjectValue(), type, bindName);
     }
 
@@ -1121,7 +1121,7 @@
      *
      * @return value of property as a MethodHandle or null.
      */
-    protected static MethodHandle getCallMethodHandle(final Object value, final MethodType type, final String bindName) {
+    private static MethodHandle getCallMethodHandle(final Object value, final MethodType type, final String bindName) {
         return value instanceof ScriptFunction ? ((ScriptFunction)value).getCallMethodHandle(type, bindName) : null;
     }
 
@@ -2107,13 +2107,13 @@
      * @param desc           call site descriptor
      * @return method handle for getter
      */
-    protected MethodHandle findGetIndexMethodHandle(final Class<?> returnType, final String name, final Class<?> elementType, final CallSiteDescriptor desc) {
+    private static MethodHandle findGetIndexMethodHandle(final Class<?> returnType, final String name, final Class<?> elementType, final CallSiteDescriptor desc) {
         if (!returnType.isPrimitive()) {
-            return findOwnMH_V(getClass(), name, returnType, elementType);
+            return findOwnMH_V(name, returnType, elementType);
         }
 
         return MH.insertArguments(
-                findOwnMH_V(getClass(), name, returnType, elementType, int.class),
+                findOwnMH_V(name, returnType, elementType, int.class),
                 2,
                 NashornCallSiteDescriptor.isOptimistic(desc) ?
                         NashornCallSiteDescriptor.getProgramPoint(desc) :
@@ -2184,7 +2184,7 @@
         FindProperty find = findProperty(name, true, NashornCallSiteDescriptor.isScope(desc), this);
 
         // If it's not a scope search, then we don't want any inherited properties except those with user defined accessors.
-        if (find != null && find.isInherited() && !find.getProperty().isAccessorProperty()) {
+        if (find != null && find.isInheritedOrdinaryProperty()) {
             // We should still check if inherited data property is not writable
             if (isExtensible() && !find.getProperty().isWritable()) {
                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
@@ -2257,11 +2257,11 @@
         }
     }
 
-    private GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
+    private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
         Context.getContextTrusted().getLogger(ObjectClassGenerator.class).warning("Megamorphic setter: ", desc, " ", name);
         final MethodType        type = desc.getMethodType().insertParameterTypes(1, Object.class);
         //never bother with ClassCastExceptionGuard for megamorphic callsites
-        final GuardedInvocation inv = findSetIndexMethod(getClass(), desc, false, type);
+        final GuardedInvocation inv = findSetIndexMethod(desc, false, type);
         return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
     }
 
@@ -2284,25 +2284,24 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
-        return findSetIndexMethod(getClass(), desc, explicitInstanceOfCheck(desc, request), desc.getMethodType());
+        return findSetIndexMethod(desc, explicitInstanceOfCheck(desc, request), desc.getMethodType());
     }
 
     /**
      * Find the appropriate SETINDEX method for an invoke dynamic call.
      *
-     * @param clazz the receiver class
      * @param desc  the call site descriptor
      * @param explicitInstanceOfCheck add an explicit instanceof check?
      * @param callType the method type at the call site
      *
      * @return GuardedInvocation to be invoked at call site.
      */
-    private static GuardedInvocation findSetIndexMethod(final Class<? extends ScriptObject> clazz, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final MethodType callType) {
+    private static GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final MethodType callType) {
         assert callType.parameterCount() == 3;
         final Class<?> keyClass   = callType.parameterType(1);
         final Class<?> valueClass = callType.parameterType(2);
 
-        MethodHandle methodHandle = findOwnMH_V(clazz, "set", void.class, keyClass, valueClass, int.class);
+        MethodHandle methodHandle = findOwnMH_V("set", void.class, keyClass, valueClass, int.class);
         methodHandle = MH.insertArguments(methodHandle, 3, NashornCallSiteDescriptor.getFlags(desc));
 
         return new GuardedInvocation(methodHandle, getScriptObjectGuard(callType, explicitInstanceOfCheck), (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
@@ -2953,18 +2952,6 @@
         return false;
     }
 
-    private boolean doesNotHaveCheckArrayKeys(final long longIndex, final long value, final int callSiteFlags) {
-        if (getMap().containsArrayKeys()) {
-            final String       key  = JSType.toString(longIndex);
-            final FindProperty find = findProperty(key, true);
-            if (find != null) {
-                setObject(find, callSiteFlags, key, value);
-                return true;
-            }
-        }
-        return false;
-    }
-
     private boolean doesNotHaveCheckArrayKeys(final long longIndex, final double value, final int callSiteFlags) {
          if (getMap().containsArrayKeys()) {
             final String       key  = JSType.toString(longIndex);
@@ -3044,7 +3031,7 @@
 
         invalidateGlobalConstant(key);
 
-        if (f != null && f.isInherited() && !f.getProperty().isAccessorProperty()) {
+        if (f != null && f.isInheritedOrdinaryProperty()) {
             final boolean isScope = isScopeFlag(callSiteFlags);
             // If the start object of the find is not this object it means the property was found inside a
             // 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
@@ -3467,15 +3454,10 @@
         return this;
     }
 
-    private static MethodHandle findOwnMH_V(final Class<? extends ScriptObject> clazz, final String name, final Class<?> rtype, final Class<?>... types) {
-        // TODO: figure out how can it work for NativeArray$Prototype etc.
+    private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findVirtual(MethodHandles.lookup(), ScriptObject.class, name, MH.type(rtype, types));
     }
 
-    private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
-        return findOwnMH_V(ScriptObject.class, name, rtype, types);
-    }
-
     private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findStatic(MethodHandles.lookup(), ScriptObject.class, name, MH.type(rtype, types));
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java	Wed Jul 05 22:00:06 2017 +0200
@@ -170,7 +170,7 @@
         assert property     != null;
 
         final MethodHandle boundHandle;
-        if (!property.isAccessorProperty() && find.isInherited()) {
+        if (find.isInheritedOrdinaryProperty()) {
             boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
         } else {
             boundHandle = methodHandle;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Wed Jul 05 21:58:30 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Wed Jul 05 22:00:06 2017 +0200
@@ -117,7 +117,7 @@
                     return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
                 }
 
-                if (find.isInherited() && !(find.getProperty().isAccessorProperty())) {
+                if (find.isInheritedOrdinaryProperty()) {
                     // If property is found in the prototype object bind the method handle directly to
                     // the proto filter instead of going through wrapper instantiation below.
                     final ScriptObject proto = wrappedReceiver.getProto();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8068972.js	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8068972: Array.splice should follow the ES6 specification
+ *
+ * @test
+ * @run
+ */
+
+
+function assertEqualArrays(a, b) {
+    Assert.assertTrue(Array.isArray(a));
+    Assert.assertTrue(Array.isArray(b));
+    Assert.assertTrue(a.length === b.length);
+    Assert.assertTrue(a.every(function(v, j) {
+        return v === b[j];
+    }));
+}
+
+var array = [1, 2, 3, 4, 5, 6, 7];
+
+var result = array.splice();
+assertEqualArrays(array, [1, 2, 3, 4, 5, 6, 7]);
+assertEqualArrays(result, []);
+
+result = array.splice(4);
+assertEqualArrays(array, [1, 2, 3, 4]);
+assertEqualArrays(result, [5, 6, 7]);
+
+result = array.splice(1, 2, -2, -3);
+assertEqualArrays(array, [1, -2, -3, 4]);
+assertEqualArrays(result, [2, 3]);
--- a/nashorn/test/script/currently-failing/logcoverage.js	Wed Jul 05 21:58:30 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * mh_coverage.js
- * Screen scrape various logs to ensure that we cover enough functionality,
- * e.g. method handle instrumentation
- *
- * @test
- * @run
- */
-
-/*
- * creates new script engine initialized with given options and
- * runs given code on it. Returns standard output captured.
- */
-
-function runScriptEngine(opts, name) {
-    var imports = new JavaImporter(
-        Packages.jdk.nashorn.api.scripting,
-        java.io, java.lang, java.util);
-
-    with(imports) {
-        var fac = new NashornScriptEngineFactory();
-        // get current System.err
-        var oldErr = System.err;
-    var oldOut = System.out;
-        var baosErr = new ByteArrayOutputStream();
-        var newErr = new PrintStream(baosErr);
-        var baosOut = new ByteArrayOutputStream();
-    var newOut = new PrintStream(baosOut);
-        try {
-            // set new standard err
-            System.setErr(newErr);
-            System.setOut(newOut);
-            var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]"));
-        var reader = new java.io.FileReader(name);
-            engine.eval(reader);
-            newErr.flush();
-        newOut.flush();
-            return new java.lang.String(baosErr.toByteArray());
-        } finally {
-            // restore System.err to old value
-            System.setErr(oldErr);
-        System.setOut(oldOut);
-        }
-    }
-}
-
-var str;
-
-var methodsCalled = [
-   'asCollector',
-   'asType',
-   'bindTo',
-   'dropArguments',
-   'explicitCastArguments',
-   'filterArguments',
-   'filterReturnValue',
-   'findStatic',
-   'findVirtual',
-   'foldArguments',
-   'getter',
-   'guardWithTest',
-   'insertArguments',
-   'methodType',
-   'setter'
-];
-
-function check(str, strs) {
-    for each (s in strs) {
-       if (str.indexOf(s) !== -1) {
-       continue;
-       }
-       print(s + " not found");
-       return;
-    }
-    print("check ok!");
-}
-
-str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js");
-str += runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/varargs.js");
-
-check(str, methodsCalled);
-check(str, ['return', 'get', 'set', '[fields]']);
-check(str, ['codegen']);
-
-print("hello, world!");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/logcoverage.js	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Screen scrape various logs to ensure that we cover enough functionality,
+ * e.g. method handle instrumentation
+ *
+ * @test
+ * @fork
+ * @option -Dnashorn.debug=true
+ */
+
+/*
+ * creates new script engine initialized with given options and
+ * runs given code on it. Returns standard output captured.
+ */
+
+function runScriptEngine(opts, name) {
+    var imports = new JavaImporter(
+            Packages.jdk.nashorn.api.scripting,
+            java.io, java.lang, java.util);
+
+    with (imports) {
+        var fac = new NashornScriptEngineFactory();
+        // get current System.err
+        var oldErr = System.err;
+        var oldOut = System.out;
+        var baosErr = new ByteArrayOutputStream();
+        var newErr = new PrintStream(baosErr);
+        var baosOut = new ByteArrayOutputStream();
+        var newOut = new PrintStream(baosOut);
+        try {
+            // set new standard err
+            System.setErr(newErr);
+            System.setOut(newOut);
+            var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]"));
+            var reader = new java.io.FileReader(name);
+            engine.eval(reader);
+            newErr.flush();
+            newOut.flush();
+            return new java.lang.String(baosErr.toByteArray());
+        } finally {
+            // restore System.err to old value
+            System.setErr(oldErr);
+            System.setOut(oldOut);
+        }
+    }
+}
+
+var str;
+
+var methodsCalled = [
+    'asCollector',
+    'asType',
+    'bindTo',
+    'dropArguments',
+    'explicitCastArguments',
+    'filterArguments',
+    'filterReturnValue',
+    'findStatic',
+    'findVirtual',
+    'foldArguments',
+    'getter',
+    'guardWithTest',
+    'insertArguments',
+    'methodType',
+    'setter'
+];
+
+function check(str, strs) {
+    for each (s in strs) {
+        if (str.indexOf(s) !== -1) {
+            continue;
+        }
+        print(s + " not found");
+        return;
+    }
+    print("check ok!");
+}
+
+str = runScriptEngine(["--log=codegen,compiler=finest,methodhandles=finest,fields=finest"], __DIR__ + "../basic/NASHORN-19.js");
+str += runScriptEngine(["--log=codegen,compiler=finest,methodhandles=finest,fields=finest"], __DIR__ + "../basic/varargs.js");
+
+check(str, methodsCalled);
+check(str, ['return', 'get', 'set', '[fields]']);
+check(str, ['codegen']);
+
+print("hello, world!");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/logcoverage.js.EXPECTED	Wed Jul 05 22:00:06 2017 +0200
@@ -0,0 +1,4 @@
+check ok!
+check ok!
+check ok!
+hello, world!