Merge jdk-9+108
authorduke
Wed, 05 Jul 2017 21:24:14 +0200
changeset 36166 257b579d8132
parent 36165 ece39bed06d6 (diff)
parent 36048 b36c9f30b87b (current diff)
child 36167 04d43de19754
child 36168 1fdc6101d10e
child 36172 0dea518903b2
child 36206 98dc79a95681
child 36212 e7d99a7fc019
child 36213 a15d59022b65
child 36255 896a46cbffee
child 36257 7f621a165e68
child 36260 94d8adc2f94d
child 36262 c9a6b8356d30
child 36263 d5333008e409
child 36266 6e85578e6e9c
child 36267 80c06d9873bd
child 36288 0114407501b7
child 36289 0a4264edc184
child 36465 de4fcf4c3672
Merge
--- a/.hgtags-top-repo	Wed Jul 05 21:22:48 2017 +0200
+++ b/.hgtags-top-repo	Wed Jul 05 21:24:14 2017 +0200
@@ -349,3 +349,4 @@
 9a38f8b4ba220708db198d08d82fd2144a64777d jdk-9+104
 be58b02c11f90b88c67e4d0e2cb5e4cf2d9b3c57 jdk-9+105
 54575d8783b3a39a2d710c28cda675d44261f9d9 jdk-9+106
+4d65eba233a8730f913734a6804910b842d2cb54 jdk-9+107
--- a/common/autoconf/flags.m4	Wed Jul 05 21:22:48 2017 +0200
+++ b/common/autoconf/flags.m4	Wed Jul 05 21:24:14 2017 +0200
@@ -123,12 +123,16 @@
 [
   # COMPILER_TARGET_BITS_FLAG  : option for selecting 32- or 64-bit output
   # COMPILER_COMMAND_FILE_FLAG : option for passing a command file to the compiler
+  # COMPILER_BINDCMD_FILE_FLAG : option for specifying a file which saves the binder
+  #                              commands produced by the link step (currently AIX only)
   if test "x$TOOLCHAIN_TYPE" = xxlc; then
     COMPILER_TARGET_BITS_FLAG="-q"
     COMPILER_COMMAND_FILE_FLAG="-f"
+    COMPILER_BINDCMD_FILE_FLAG="-bloadmap:"
   else
     COMPILER_TARGET_BITS_FLAG="-m"
     COMPILER_COMMAND_FILE_FLAG="@"
+    COMPILER_BINDCMD_FILE_FLAG=""
 
     # The solstudio linker does not support @-files.
     if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
@@ -152,6 +156,7 @@
   fi
   AC_SUBST(COMPILER_TARGET_BITS_FLAG)
   AC_SUBST(COMPILER_COMMAND_FILE_FLAG)
+  AC_SUBST(COMPILER_BINDCMD_FILE_FLAG)
 
   # FIXME: figure out if we should select AR flags depending on OS or toolchain.
   if test "x$OPENJDK_TARGET_OS" = xmacosx; then
@@ -294,10 +299,23 @@
     SET_SHARED_LIBRARY_NAME='-h [$]1'
     SET_SHARED_LIBRARY_MAPFILE='-M[$]1'
   elif test "x$TOOLCHAIN_TYPE" = xxlc; then
-    PICFLAG="-qpic=large"
+    # '-qpic' defaults to 'qpic=small'. This means that the compiler generates only
+    # one instruction for accessing the TOC. If the TOC grows larger than 64K, the linker
+    # will have to patch this single instruction with a call to some out-of-order code which
+    # does the load from the TOC. This is of course slow. But in that case we also would have
+    # to use '-bbigtoc' for linking anyway so we could also change the PICFLAG to 'qpic=large'.
+    # With 'qpic=large' the compiler will by default generate a two-instruction sequence which
+    # can be patched directly by the linker and does not require a jump to out-of-order code.
+    # Another alternative instead of using 'qpic=large -bbigtoc' may be to use '-qminimaltoc'
+    # instead. This creates a distinct TOC for every compilation unit (and thus requires two
+    # loads for accessing a global variable). But there are rumors that this may be seen as a
+    # 'performance feature' because of improved code locality of the symbols used in a
+    # compilation unit.
+    PICFLAG="-qpic"
+    JVM_CFLAGS="$JVM_CFLAGS $PICFLAG"
     C_FLAG_REORDER=''
     CXX_FLAG_REORDER=''
-    SHARED_LIBRARY_FLAGS="-qmkshrobj"
+    SHARED_LIBRARY_FLAGS="-qmkshrobj -bM:SRE -bnoentry"
     SET_EXECUTABLE_ORIGIN=""
     SET_SHARED_LIBRARY_ORIGIN=''
     SET_SHARED_LIBRARY_NAME=''
@@ -835,7 +853,7 @@
     LDFLAGS_CXX_SOLSTUDIO="-norunpath"
     LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LDFLAGS_CXX_SOLSTUDIO -xnolib"
   elif test "x$TOOLCHAIN_TYPE" = xxlc; then
-    LDFLAGS_XLC="-brtl -bnolibpath -bexpall -bernotok"
+    LDFLAGS_XLC="-b64 -brtl -bnolibpath -bexpall -bernotok"
     LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_XLC"
   fi
 
@@ -891,6 +909,7 @@
   AC_SUBST(JDKLIB_LIBS)
   AC_SUBST(JDKEXE_LIBS)
   AC_SUBST(LDFLAGS_CXX_JDK)
+  AC_SUBST(LDFLAGS_HASH_STYLE)
 
   LDFLAGS_TESTLIB="$LDFLAGS_JDKLIB"
   LDFLAGS_TESTEXE="$LDFLAGS_JDKEXE"
--- a/common/autoconf/generated-configure.sh	Wed Jul 05 21:22:48 2017 +0200
+++ b/common/autoconf/generated-configure.sh	Wed Jul 05 21:24:14 2017 +0200
@@ -701,6 +701,7 @@
 ZERO_ARCHFLAG
 LDFLAGS_TESTEXE
 LDFLAGS_TESTLIB
+LDFLAGS_HASH_STYLE
 LDFLAGS_CXX_JDK
 JDKEXE_LIBS
 JDKLIB_LIBS
@@ -743,6 +744,7 @@
 CC_OUT_OPTION
 STRIPFLAGS
 ARFLAGS
+COMPILER_BINDCMD_FILE_FLAG
 COMPILER_COMMAND_FILE_FLAG
 COMPILER_TARGET_BITS_FLAG
 JT_HOME
@@ -4230,7 +4232,7 @@
 
 
 #
-# 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
@@ -4860,7 +4862,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1455271513
+DATE_WHEN_GENERATED=1456136781
 
 ###############################################################################
 #
@@ -45391,12 +45393,16 @@
 
   # COMPILER_TARGET_BITS_FLAG  : option for selecting 32- or 64-bit output
   # COMPILER_COMMAND_FILE_FLAG : option for passing a command file to the compiler
+  # COMPILER_BINDCMD_FILE_FLAG : option for specifying a file which saves the binder
+  #                              commands produced by the link step (currently AIX only)
   if test "x$TOOLCHAIN_TYPE" = xxlc; then
     COMPILER_TARGET_BITS_FLAG="-q"
     COMPILER_COMMAND_FILE_FLAG="-f"
+    COMPILER_BINDCMD_FILE_FLAG="-bloadmap:"
   else
     COMPILER_TARGET_BITS_FLAG="-m"
     COMPILER_COMMAND_FILE_FLAG="@"
+    COMPILER_BINDCMD_FILE_FLAG=""
 
     # The solstudio linker does not support @-files.
     if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
@@ -45424,6 +45430,7 @@
 
 
 
+
   # FIXME: figure out if we should select AR flags depending on OS or toolchain.
   if test "x$OPENJDK_TARGET_OS" = xmacosx; then
     ARFLAGS="-r"
@@ -46198,10 +46205,23 @@
     SET_SHARED_LIBRARY_NAME='-h $1'
     SET_SHARED_LIBRARY_MAPFILE='-M$1'
   elif test "x$TOOLCHAIN_TYPE" = xxlc; then
-    PICFLAG="-qpic=large"
+    # '-qpic' defaults to 'qpic=small'. This means that the compiler generates only
+    # one instruction for accessing the TOC. If the TOC grows larger than 64K, the linker
+    # will have to patch this single instruction with a call to some out-of-order code which
+    # does the load from the TOC. This is of course slow. But in that case we also would have
+    # to use '-bbigtoc' for linking anyway so we could also change the PICFLAG to 'qpic=large'.
+    # With 'qpic=large' the compiler will by default generate a two-instruction sequence which
+    # can be patched directly by the linker and does not require a jump to out-of-order code.
+    # Another alternative instead of using 'qpic=large -bbigtoc' may be to use '-qminimaltoc'
+    # instead. This creates a distinct TOC for every compilation unit (and thus requires two
+    # loads for accessing a global variable). But there are rumors that this may be seen as a
+    # 'performance feature' because of improved code locality of the symbols used in a
+    # compilation unit.
+    PICFLAG="-qpic"
+    JVM_CFLAGS="$JVM_CFLAGS $PICFLAG"
     C_FLAG_REORDER=''
     CXX_FLAG_REORDER=''
-    SHARED_LIBRARY_FLAGS="-qmkshrobj"
+    SHARED_LIBRARY_FLAGS="-qmkshrobj -bM:SRE -bnoentry"
     SET_EXECUTABLE_ORIGIN=""
     SET_SHARED_LIBRARY_ORIGIN=''
     SET_SHARED_LIBRARY_NAME=''
@@ -46824,7 +46844,7 @@
     LDFLAGS_CXX_SOLSTUDIO="-norunpath"
     LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LDFLAGS_CXX_SOLSTUDIO -xnolib"
   elif test "x$TOOLCHAIN_TYPE" = xxlc; then
-    LDFLAGS_XLC="-brtl -bnolibpath -bexpall -bernotok"
+    LDFLAGS_XLC="-b64 -brtl -bnolibpath -bexpall -bernotok"
     LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_XLC"
   fi
 
@@ -46881,6 +46901,7 @@
 
 
 
+
   LDFLAGS_TESTLIB="$LDFLAGS_JDKLIB"
   LDFLAGS_TESTEXE="$LDFLAGS_JDKEXE"
 
@@ -58630,7 +58651,8 @@
 
 
   # Setup libm (the maths library)
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5
+  if test "x$OPENJDK_TARGET_OS" != "xwindows"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5
 $as_echo_n "checking for cos in -lm... " >&6; }
 if ${ac_cv_lib_m_cos+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -58675,12 +58697,15 @@
 
 else
 
-      { $as_echo "$as_me:${as_lineno-$LINENO}: Maths library was not found" >&5
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Maths library was not found" >&5
 $as_echo "$as_me: Maths library was not found" >&6;}
 
 fi
 
-  LIBM=-lm
+    LIBM="-lm"
+  else
+    LIBM=""
+  fi
 
 
   # Setup libdl (for dynamic library loading)
--- a/common/autoconf/libraries.m4	Wed Jul 05 21:22:48 2017 +0200
+++ b/common/autoconf/libraries.m4	Wed Jul 05 21:24:14 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
@@ -160,10 +160,14 @@
 AC_DEFUN_ONCE([LIB_SETUP_MISC_LIBS],
 [
   # Setup libm (the maths library)
-  AC_CHECK_LIB(m, cos, [], [
-      AC_MSG_NOTICE([Maths library was not found])
-  ])
-  LIBM=-lm
+  if test "x$OPENJDK_TARGET_OS" != "xwindows"; then
+    AC_CHECK_LIB(m, cos, [], [
+        AC_MSG_NOTICE([Maths library was not found])
+    ])
+    LIBM="-lm"
+  else
+    LIBM=""
+  fi
   AC_SUBST(LIBM)
 
   # Setup libdl (for dynamic library loading)
--- a/common/autoconf/spec.gmk.in	Wed Jul 05 21:22:48 2017 +0200
+++ b/common/autoconf/spec.gmk.in	Wed Jul 05 21:24:14 2017 +0200
@@ -314,6 +314,10 @@
 # Option used to pass a command file to the compiler
 COMPILER_COMMAND_FILE_FLAG:=@COMPILER_COMMAND_FILE_FLAG@
 
+# Option for specifying a file which saves the binder commands
+# produced by the link step (for debugging, currently AIX only)
+COMPILER_BINDCMD_FILE_FLAG:=@COMPILER_BINDCMD_FILE_FLAG@
+
 CC_OUT_OPTION:=@CC_OUT_OPTION@
 EXE_OUT_OPTION:=@EXE_OUT_OPTION@
 LD_OUT_OPTION:=@LD_OUT_OPTION@
@@ -351,6 +355,8 @@
 CFLAGS_JDKEXE:=@CFLAGS_JDKEXE@
 CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@
 
+LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@
+
 CXX:=@FIXPATH@ @CCACHE@ @ICECC@ @CXX@
 
 CPP:=@FIXPATH@ @CPP@
--- a/corba/.hgtags	Wed Jul 05 21:22:48 2017 +0200
+++ b/corba/.hgtags	Wed Jul 05 21:24:14 2017 +0200
@@ -349,3 +349,4 @@
 e385e95e6101711d5c63e7b1a827e99b6ec7a1cc jdk-9+104
 64006ae915b3aa85ac7e6fac679024d2da7fe526 jdk-9+105
 8ec4f97943fe56f93e4621f622b56b7144c0181a jdk-9+106
+49202432b69445164a42be7cbdf74ed5fce98157 jdk-9+107
--- a/hotspot/.hgignore	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/.hgignore	Wed Jul 05 21:24:14 2017 +0200
@@ -10,7 +10,6 @@
 .igv.log
 ^.hgtip
 .DS_Store
-\.class$
 ^\.mx.jvmci/env
 ^\.mx.jvmci/.*\.pyc
 ^\.mx.jvmci/eclipse-launches/.*
--- a/hotspot/.hgtags	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/.hgtags	Wed Jul 05 21:24:14 2017 +0200
@@ -509,3 +509,4 @@
 534c50395957c6025fb6627e93b35756f8d48a08 jdk-9+104
 266fa9bb5297bf02cb2a7b038b10a109817d2b48 jdk-9+105
 7232de4c17c37f60aecec4f3191090bd3d41d334 jdk-9+106
+c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107
--- a/hotspot/make/bsd/makefiles/arm.make	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/make/bsd/makefiles/arm.make	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2008, 2013, 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
@@ -24,8 +24,4 @@
 
 Obj_Files += bsd_arm.o
 
-ifneq ($(EXT_LIBS_PATH),)
-  LIBS += $(EXT_LIBS_PATH)/sflt_glibc.a 
-endif
-
 CFLAGS += -DVM_LITTLE_ENDIAN
--- a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -54,6 +54,7 @@
 define_pd_global(intx, InteriorEntryAlignment,       16);
 define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K));
 define_pd_global(intx, LoopUnrollLimit,              60);
+define_pd_global(intx, LoopPercentProfileLimit,      10);
 // InitialCodeCacheSize derived from specjbb2000 run.
 define_pd_global(intx, InitialCodeCacheSize,         2496*K); // Integral multiple of CodeCacheExpansionSize
 define_pd_global(intx, CodeCacheExpansionSize,       64*K);
--- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2015, Red Hat Inc. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -32,7 +32,6 @@
 // Sets the default values for platform dependent flags used by the runtime system.
 // (see globals.hpp)
 
-define_pd_global(bool, ConvertSleepToYield,      true);
 define_pd_global(bool, ShareVtableStubs,         true);
 define_pd_global(bool, NeedsDeoptSuspend,        false); // only register window machines need this
 
--- a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp	Wed Jul 05 21:24:14 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
@@ -30,39 +30,151 @@
 #include "vmreg_aarch64.inline.hpp"
 
 jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) {
-  Unimplemented();
-  return 0;
+  if (inst->is_call() || inst->is_jump() || inst->is_blr()) {
+    return pc_offset + NativeCall::instruction_size;
+  } else if (inst->is_general_jump()) {
+    return pc_offset + NativeGeneralJump::instruction_size;
+  } else {
+    JVMCI_ERROR_0("unsupported type of instruction for call site");
+  }
 }
 
 void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
-  Unimplemented();
+  address pc = _instructions->start() + pc_offset;
+  Handle obj = HotSpotObjectConstantImpl::object(constant);
+  jobject value = JNIHandles::make_local(obj());
+  if (HotSpotObjectConstantImpl::compressed(constant)) {
+    int oop_index = _oop_recorder->find_index(value);
+    RelocationHolder rspec = oop_Relocation::spec(oop_index);
+    _instructions->relocate(pc, rspec, 1);
+    Unimplemented();
+  } else {
+    NativeMovConstReg* move = nativeMovConstReg_at(pc);
+    move->set_data((intptr_t) value);
+    int oop_index = _oop_recorder->find_index(value);
+    RelocationHolder rspec = oop_Relocation::spec(oop_index);
+    _instructions->relocate(pc, rspec);
+  }
 }
 
 void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) {
-  Unimplemented();
+  address pc = _instructions->start() + pc_offset;
+  if (HotSpotMetaspaceConstantImpl::compressed(constant)) {
+    narrowKlass narrowOop = record_narrow_metadata_reference(constant, CHECK);
+    TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop);
+    Unimplemented();
+  } else {
+    NativeMovConstReg* move = nativeMovConstReg_at(pc);
+    Metadata* reference = record_metadata_reference(constant, CHECK);
+    move->set_data((intptr_t) reference);
+    TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference));
+  }
 }
 
-void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
-  Unimplemented();
+void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) {
+  address pc = _instructions->start() + pc_offset;
+  NativeInstruction* inst = nativeInstruction_at(pc);
+  if (inst->is_adr_aligned()) {
+    address dest = _constants->start() + data_offset;
+    _instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS));
+    TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset);
+  } else {
+    JVMCI_ERROR("unknown load or move instruction at " PTR_FORMAT, p2i(pc));
+  }
 }
 
 void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) {
-  Unimplemented();
+  address pc = (address) inst;
+  if (inst->is_call()) {
+    NativeCall* call = nativeCall_at(pc);
+    call->set_destination((address) foreign_call_destination);
+    _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec());
+  } else if (inst->is_jump()) {
+    NativeJump* jump = nativeJump_at(pc);
+    jump->set_jump_destination((address) foreign_call_destination);
+    _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec());
+  } else if (inst->is_general_jump()) {
+    NativeGeneralJump* jump = nativeGeneralJump_at(pc);
+    jump->set_jump_destination((address) foreign_call_destination);
+    _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec());
+  } else {
+    JVMCI_ERROR("unknown call or jump instruction at " PTR_FORMAT, p2i(pc));
+  }
+  TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
 }
 
 void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) {
-  Unimplemented();
+#ifdef ASSERT
+  Method* method = NULL;
+  // we need to check, this might also be an unresolved method
+  if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) {
+    method = getMethodFromHotSpotMethod(hotspot_method());
+  }
+#endif
+  switch (_next_call_type) {
+    case INLINE_INVOKE:
+      break;
+    case INVOKEVIRTUAL:
+    case INVOKEINTERFACE: {
+      assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface");
+      NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
+      call->set_destination(SharedRuntime::get_resolve_virtual_call_stub());
+      _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc));
+      break;
+    }
+    case INVOKESTATIC: {
+      assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic");
+      NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
+      call->set_destination(SharedRuntime::get_resolve_static_call_stub());
+      _instructions->relocate(call->instruction_address(), relocInfo::static_call_type);
+      break;
+    }
+    case INVOKESPECIAL: {
+      assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial");
+      NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
+      call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub());
+      _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type);
+      break;
+    }
+    default:
+      JVMCI_ERROR("invalid _next_call_type value");
+      break;
+  }
 }
 
 void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) {
-  Unimplemented();
+  switch (mark) {
+    case POLL_NEAR:
+      JVMCI_ERROR("unimplemented");
+      break;
+    case POLL_FAR:
+      _instructions->relocate(pc, relocInfo::poll_type);
+      break;
+    case POLL_RETURN_NEAR:
+      JVMCI_ERROR("unimplemented");
+      break;
+    case POLL_RETURN_FAR:
+      _instructions->relocate(pc, relocInfo::poll_return_type);
+      break;
+    default:
+      JVMCI_ERROR("invalid mark value");
+      break;
+  }
 }
 
 // convert JVMCI register indices (as used in oop maps) to HotSpot registers
 VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) {
-  return NULL;
+  if (jvmci_reg < RegisterImpl::number_of_registers) {
+    return as_Register(jvmci_reg)->as_VMReg();
+  } else {
+    jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers;
+    if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) {
+      return as_FloatRegister(floatRegisterNumber)->as_VMReg();
+    }
+    JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg);
+  }
 }
 
 bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
-  return false;
+  return !hotspotRegister->is_FloatRegister();
 }
--- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -136,7 +136,7 @@
     MacroAssembler::pd_patch_instruction(instruction_address(), (address)x);
     ICache::invalidate_range(instruction_address(), instruction_size);
   }
-};
+}
 
 void NativeMovConstReg::print() {
   tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT,
@@ -208,6 +208,32 @@
 
 //-------------------------------------------------------------------
 
+address NativeGeneralJump::jump_destination() const {
+  NativeMovConstReg* move = nativeMovConstReg_at(instruction_address());
+  address dest = (address) move->data();
+
+  // We use jump to self as the unresolved address which the inline
+  // cache code (and relocs) know about
+
+  // return -1 if jump to self
+  dest = (dest == (address) this) ? (address) -1 : dest;
+  return dest;
+}
+
+void NativeGeneralJump::set_jump_destination(address dest) {
+  NativeMovConstReg* move = nativeMovConstReg_at(instruction_address());
+
+  // We use jump to self as the unresolved address which the inline
+  // cache code (and relocs) know about
+  if (dest == (address) -1) {
+    dest = instruction_address();
+  }
+
+  move->set_data((uintptr_t) dest);
+};
+
+//-------------------------------------------------------------------
+
 bool NativeInstruction::is_safepoint_poll() {
   // a safepoint_poll is implemented in two steps as either
   //
@@ -249,6 +275,22 @@
           Instruction_aarch64::extract(insn, 4, 0) == 0b11111);
 }
 
+bool NativeInstruction::is_general_jump() {
+  if (is_movz()) {
+    NativeInstruction* inst1 = nativeInstruction_at(addr_at(instruction_size * 1));
+    if (inst1->is_movk()) {
+      NativeInstruction* inst2 = nativeInstruction_at(addr_at(instruction_size * 2));
+      if (inst2->is_movk()) {
+        NativeInstruction* inst3 = nativeInstruction_at(addr_at(instruction_size * 3));
+        if (inst3->is_blr()) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
 bool NativeInstruction::is_movz() {
   return Instruction_aarch64::extract(int_at(0), 30, 23) == 0b10100101;
 }
--- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -54,11 +54,22 @@
   friend class Relocation;
   friend bool is_NativeCallTrampolineStub_at(address);
  public:
-  enum { instruction_size = 4 };
+  enum {
+    instruction_size = 4
+  };
+
+  juint encoding() const {
+    return uint_at(0);
+  }
+
+  bool is_blr()                      const { return (encoding() & 0xfffffc1f) == 0xd63f0000; }
+  bool is_adr_aligned()              const { return (encoding() & 0xff000000) == 0x10000000; } // adr Xn, <label>, where label is aligned to 4 bytes (address of instruction).
+
   inline bool is_nop();
   inline bool is_illegal();
   inline bool is_return();
   bool is_jump();
+  bool is_general_jump();
   inline bool is_jump_or_nop();
   inline bool is_cond_jump();
   bool is_safepoint_poll();
@@ -341,11 +352,15 @@
 // An interface for accessing/manipulating native leal instruction of form:
 //        leal reg, [reg + offset]
 
-class NativeLoadAddress: public NativeMovRegMem {
-  static const bool has_rex = true;
-  static const int rex_size = 1;
+class NativeLoadAddress: public NativeInstruction {
+  enum AArch64_specific_constants {
+    instruction_size            =    4,
+    instruction_offset          =    0,
+    data_offset                 =    0,
+    next_instruction_offset     =    4
+  };
+
  public:
-
   void verify();
   void print ();
 
@@ -398,6 +413,10 @@
     data_offset                 =    0,
     next_instruction_offset     =    4 * 4
   };
+
+  address jump_destination() const;
+  void set_jump_destination(address dest);
+
   static void insert_unconditional(address code_pos, address entry);
   static void replace_mt_safe(address instr_addr, address code_buffer);
   static void verify();
--- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -54,6 +54,7 @@
 define_pd_global(bool, UseTLAB,                      true);
 define_pd_global(bool, ResizeTLAB,                   true);
 define_pd_global(intx, LoopUnrollLimit,              60);
+define_pd_global(intx, LoopPercentProfileLimit,      10);
 
 // Peephole and CISC spilling both break the graph, and so make the
 // scheduler sick.
--- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp	Wed Jul 05 21:24:14 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.
  * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -32,7 +32,6 @@
 // Sets the default values for platform dependent flags used by the runtime system.
 // (see globals.hpp)
 
-define_pd_global(bool, ConvertSleepToYield,   true);
 define_pd_global(bool, ShareVtableStubs,      false); // Improves performance markedly for mtrt and compress.
 define_pd_global(bool, NeedsDeoptSuspend,     false); // Only register window machines need this.
 
--- a/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp	Wed Jul 05 21:24:14 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
@@ -42,7 +42,7 @@
   Unimplemented();
 }
 
-void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
+void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) {
   Unimplemented();
 }
 
--- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -52,6 +52,7 @@
 define_pd_global(bool, UseTLAB,                      true);
 define_pd_global(bool, ResizeTLAB,                   true);
 define_pd_global(intx, LoopUnrollLimit,              60); // Design center runs on 1.3.1
+define_pd_global(intx, LoopPercentProfileLimit,      10);
 define_pd_global(intx, MinJumpTableSize,             5);
 
 // Peephole and CISC spilling both break the graph, and so makes the
--- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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,7 +37,6 @@
 // the load of the dispatch address and hence the jmp would still go to the location
 // according to the prior table. So, we let the thread continue and let it block by itself.
 define_pd_global(bool, DontYieldALot,               true);  // yield no more than 100 times per second
-define_pd_global(bool, ConvertSleepToYield,         false); // do not convert sleep(0) to yield. Helps GUI
 define_pd_global(bool, ShareVtableStubs,            false); // improves performance markedly for mtrt and compress
 define_pd_global(bool, NeedsDeoptSuspend,           true); // register window machines need this
 
--- a/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp	Wed Jul 05 21:24:14 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
@@ -85,7 +85,7 @@
   }
 }
 
-void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
+void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) {
   address pc = _instructions->start() + pc_offset;
   NativeInstruction* inst = nativeInstruction_at(pc);
   NativeInstruction* inst1 = nativeInstruction_at(pc + 4);
--- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -2015,23 +2015,33 @@
   int vep_offset = ((intptr_t)__ pc()) - start;
 
 #ifdef COMPILER1
-  if (InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) {
-    // Object.hashCode can pull the hashCode from the header word
-    // instead of doing a full VM transition once it's been computed.
-    // Since hashCode is usually polymorphic at call sites we can't do
-    // this optimization at the call site without a lot of work.
+  if ((InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) || (method->intrinsic_id() == vmIntrinsics::_identityHashCode)) {
+    // Object.hashCode, System.identityHashCode can pull the hashCode from the
+    // header word instead of doing a full VM transition once it's been computed.
+    // Since hashCode is usually polymorphic at call sites we can't do this
+    // optimization at the call site without a lot of work.
     Label slowCase;
-    Register receiver             = O0;
+    Label done;
+    Register obj_reg              = O0;
     Register result               = O0;
     Register header               = G3_scratch;
     Register hash                 = G3_scratch; // overwrite header value with hash value
     Register mask                 = G1;         // to get hash field from header
 
+    // Unlike for Object.hashCode, System.identityHashCode is static method and
+    // gets object as argument instead of the receiver.
+    if (method->intrinsic_id() == vmIntrinsics::_identityHashCode) {
+      assert(method->is_static(), "method should be static");
+      // return 0 for null reference input
+      __ br_null(obj_reg, false, Assembler::pn, done);
+      __ delayed()->mov(obj_reg, hash);
+    }
+
     // Read the header and build a mask to get its hash field.  Give up if the object is not unlocked.
     // We depend on hash_mask being at most 32 bits and avoid the use of
     // hash_mask_in_place because it could be larger than 32 bits in a 64-bit
     // vm: see markOop.hpp.
-    __ ld_ptr(receiver, oopDesc::mark_offset_in_bytes(), header);
+    __ ld_ptr(obj_reg, oopDesc::mark_offset_in_bytes(), header);
     __ sethi(markOopDesc::hash_mask, mask);
     __ btst(markOopDesc::unlocked_value, header);
     __ br(Assembler::zero, false, Assembler::pn, slowCase);
@@ -2054,6 +2064,7 @@
     __ delayed()->nop();
 
     // leaf return.
+    __ bind(done);
     __ retl();
     __ delayed()->mov(hash, result);
     __ bind(slowCase);
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -2361,7 +2361,7 @@
 void Assembler::movdqu(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
   attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
   simd_prefix(dst, xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x6F);
@@ -2398,7 +2398,7 @@
 void Assembler::vmovdqu(XMMRegister dst, Address src) {
   assert(UseAVX > 0, "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+  InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
   attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
   vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x6F);
@@ -2486,7 +2486,7 @@
 void Assembler::evmovdqul(XMMRegister dst, Address src, int vector_len) {
   assert(VM_Version::supports_evex(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false , /* uses_vl */ true);
   attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
   vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x6F);
@@ -2515,7 +2515,7 @@
 void Assembler::evmovdquq(XMMRegister dst, Address src, int vector_len) {
   assert(VM_Version::supports_evex(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+  InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
   attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
   vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x6F);
@@ -2640,7 +2640,7 @@
 
 void Assembler::movsd(XMMRegister dst, XMMRegister src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x10);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -2649,7 +2649,7 @@
 void Assembler::movsd(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
   simd_prefix(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x10);
@@ -2668,7 +2668,7 @@
 
 void Assembler::movss(XMMRegister dst, XMMRegister src) {
   NOT_LP64(assert(VM_Version::supports_sse(), ""));
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x10);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -2677,7 +2677,7 @@
 void Assembler::movss(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
   simd_prefix(dst, xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x10);
@@ -2782,7 +2782,7 @@
 void Assembler::mulsd(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
   simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x59);
@@ -2791,7 +2791,7 @@
 
 void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x59);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -2800,7 +2800,7 @@
 void Assembler::mulss(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
   simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x59);
@@ -2809,7 +2809,7 @@
 
 void Assembler::mulss(XMMRegister dst, XMMRegister src) {
   NOT_LP64(assert(VM_Version::supports_sse(), ""));
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x59);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -3993,7 +3993,7 @@
 
 void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x51);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -4002,7 +4002,7 @@
 void Assembler::sqrtsd(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
   simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x51);
@@ -4011,7 +4011,7 @@
 
 void Assembler::sqrtss(XMMRegister dst, XMMRegister src) {
   NOT_LP64(assert(VM_Version::supports_sse(), ""));
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x51);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -4024,7 +4024,7 @@
 void Assembler::sqrtss(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
   simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x51);
@@ -4078,7 +4078,7 @@
 
 void Assembler::subsd(XMMRegister dst, XMMRegister src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x5C);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -4087,7 +4087,7 @@
 void Assembler::subsd(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse2(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
   simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x5C);
@@ -4096,7 +4096,7 @@
 
 void Assembler::subss(XMMRegister dst, XMMRegister src) {
   NOT_LP64(assert(VM_Version::supports_sse(), ""));
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false , /* uses_vl */ false);
   int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x5C);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -4105,7 +4105,7 @@
 void Assembler::subss(XMMRegister dst, Address src) {
   NOT_LP64(assert(VM_Version::supports_sse(), ""));
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
   simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x5C);
@@ -4293,7 +4293,7 @@
 void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, Address src) {
   assert(VM_Version::supports_avx(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
@@ -4303,7 +4303,7 @@
 
 void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, XMMRegister src) {
   assert(VM_Version::supports_avx(), "");
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x58);
@@ -4313,7 +4313,7 @@
 void Assembler::vaddss(XMMRegister dst, XMMRegister nds, Address src) {
   assert(VM_Version::supports_avx(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
@@ -4323,7 +4323,7 @@
 
 void Assembler::vaddss(XMMRegister dst, XMMRegister nds, XMMRegister src) {
   assert(VM_Version::supports_avx(), "");
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x58);
@@ -4333,7 +4333,7 @@
 void Assembler::vdivsd(XMMRegister dst, XMMRegister nds, Address src) {
   assert(VM_Version::supports_avx(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
@@ -4343,7 +4343,7 @@
 
 void Assembler::vdivsd(XMMRegister dst, XMMRegister nds, XMMRegister src) {
   assert(VM_Version::supports_avx(), "");
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x5E);
@@ -4353,7 +4353,7 @@
 void Assembler::vdivss(XMMRegister dst, XMMRegister nds, Address src) {
   assert(VM_Version::supports_avx(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
@@ -4363,7 +4363,7 @@
 
 void Assembler::vdivss(XMMRegister dst, XMMRegister nds, XMMRegister src) {
   assert(VM_Version::supports_avx(), "");
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x5E);
@@ -4373,7 +4373,7 @@
 void Assembler::vmulsd(XMMRegister dst, XMMRegister nds, Address src) {
   assert(VM_Version::supports_avx(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
@@ -4383,7 +4383,7 @@
 
 void Assembler::vmulsd(XMMRegister dst, XMMRegister nds, XMMRegister src) {
   assert(VM_Version::supports_avx(), "");
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x59);
@@ -4393,7 +4393,7 @@
 void Assembler::vmulss(XMMRegister dst, XMMRegister nds, Address src) {
   assert(VM_Version::supports_avx(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
@@ -4403,7 +4403,7 @@
 
 void Assembler::vmulss(XMMRegister dst, XMMRegister nds, XMMRegister src) {
   assert(VM_Version::supports_avx(), "");
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x59);
@@ -4413,7 +4413,7 @@
 void Assembler::vsubsd(XMMRegister dst, XMMRegister nds, Address src) {
   assert(VM_Version::supports_avx(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
@@ -4423,7 +4423,7 @@
 
 void Assembler::vsubsd(XMMRegister dst, XMMRegister nds, XMMRegister src) {
   assert(VM_Version::supports_avx(), "");
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
   emit_int8(0x5C);
@@ -4433,7 +4433,7 @@
 void Assembler::vsubss(XMMRegister dst, XMMRegister nds, Address src) {
   assert(VM_Version::supports_avx(), "");
   InstructionMark im(this);
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
@@ -4443,7 +4443,7 @@
 
 void Assembler::vsubss(XMMRegister dst, XMMRegister nds, XMMRegister src) {
   assert(VM_Version::supports_avx(), "");
-  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+  InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false);
   int nds_enc = nds->is_valid() ? nds->encoding() : 0;
   int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
   emit_int8(0x5C);
@@ -5901,7 +5901,7 @@
 // duplicate 1-byte integer data from src into 16||32|64 locations in dest : requires AVX512BW and AVX512VL
 void Assembler::evpbroadcastb(XMMRegister dst, XMMRegister src, int vector_len) {
   assert(VM_Version::supports_evex(), "");
-  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
   int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
   emit_int8(0x78);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -5911,7 +5911,7 @@
   assert(VM_Version::supports_evex(), "");
   assert(dst != xnoreg, "sanity");
   InstructionMark im(this);
-  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_8bit);
   // swap src<->dst for encoding
   vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -5922,7 +5922,7 @@
 // duplicate 2-byte integer data from src into 8|16||32 locations in dest : requires AVX512BW and AVX512VL
 void Assembler::evpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len) {
   assert(VM_Version::supports_evex(), "");
-  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
   int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
   emit_int8(0x79);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -5932,7 +5932,7 @@
   assert(VM_Version::supports_evex(), "");
   assert(dst != xnoreg, "sanity");
   InstructionMark im(this);
-  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
   attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit);
   // swap src<->dst for encoding
   vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -6027,7 +6027,7 @@
 // duplicate 1-byte integer data from src into 16||32|64 locations in dest : requires AVX512BW and AVX512VL
 void Assembler::evpbroadcastb(XMMRegister dst, Register src, int vector_len) {
   assert(VM_Version::supports_evex(), "");
-  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
   int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
   emit_int8(0x7A);
   emit_int8((unsigned char)(0xC0 | encode));
@@ -6036,7 +6036,7 @@
 // duplicate 2-byte integer data from src into 8|16||32 locations in dest : requires AVX512BW and AVX512VL
 void Assembler::evpbroadcastw(XMMRegister dst, Register src, int vector_len) {
   assert(VM_Version::supports_evex(), "");
-  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+  InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
   int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
   emit_int8(0x7B);
   emit_int8((unsigned char)(0xC0 | encode));
--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -2044,11 +2044,11 @@
 class InstructionAttr {
 public:
   InstructionAttr(
-    int vector_len,
-    bool rex_vex_w,
-    bool legacy_mode,
-    bool no_reg_mask,
-    bool uses_vl)
+    int vector_len,     // The length of vector to be applied in encoding - for both AVX and EVEX
+    bool rex_vex_w,     // Width of data: if 32-bits or less, false, else if 64-bit or specially defined, true
+    bool legacy_mode,   // Details if either this instruction is conditionally encoded to AVX or earlier if true else possibly EVEX
+    bool no_reg_mask,   // when true, k0 is used when EVEX encoding is chosen, else k1 is used under the same condition
+    bool uses_vl)       // This instruction may have legacy constraints based on vector length for EVEX
     :
       _avx_vector_len(vector_len),
       _rex_vex_w(rex_vex_w),
--- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -46,6 +46,7 @@
 define_pd_global(intx, ConditionalMoveLimit,         3);
 define_pd_global(intx, FreqInlineSize,               325);
 define_pd_global(intx, MinJumpTableSize,             10);
+define_pd_global(intx, LoopPercentProfileLimit,      30);
 #ifdef AMD64
 define_pd_global(intx, INTPRESSURE,                  13);
 define_pd_global(intx, FLOATPRESSURE,                14);
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -31,7 +31,6 @@
 // Sets the default values for platform dependent flags used by the runtime system.
 // (see globals.hpp)
 
-define_pd_global(bool, ConvertSleepToYield,      true);
 define_pd_global(bool, ShareVtableStubs,         true);
 define_pd_global(bool, NeedsDeoptSuspend,        false); // only register window machines need this
 
--- a/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp	Wed Jul 05 21:24:14 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
@@ -101,7 +101,7 @@
   }
 }
 
-void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
+void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) {
   address pc = _instructions->start() + pc_offset;
 
   address operand = Assembler::locate_operand(pc, Assembler::disp32_operand);
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -7840,7 +7840,9 @@
   Label COMPARE_WIDE_VECTORS_LOOP_FAILED;  // used only _LP64 && AVX3
   int stride, stride2, adr_stride, adr_stride1, adr_stride2;
   int stride2x2 = 0x40;
-  Address::ScaleFactor scale, scale1, scale2;
+  Address::ScaleFactor scale = Address::no_scale;
+  Address::ScaleFactor scale1 = Address::no_scale;
+  Address::ScaleFactor scale2 = Address::no_scale;
 
   if (ae != StrIntrinsicNode::LL) {
     stride2x2 = 0x20;
@@ -7894,9 +7896,9 @@
       stride = 8;
     }
   } else {
-    scale = Address::no_scale;  // not used
     scale1 = Address::times_1;
     scale2 = Address::times_2;
+    // scale not used
     stride = 8;
   }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86.cpp	Wed Jul 05 21:24:14 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.
+ *
+ * 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 "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "vmreg_x86.inline.hpp"
+#ifdef COMPILER1
+#include "c1/c1_Runtime1.hpp"
+#endif //COMPILER1
+
+#define __ masm->
+
+#ifdef COMPILER1
+// ---------------------------------------------------------------------------
+// Object.hashCode, System.identityHashCode can pull the hashCode from the
+// header word instead of doing a full VM transition once it's been computed.
+// Since hashCode is usually polymorphic at call sites we can't do this
+// optimization at the call site without a lot of work.
+void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* masm,
+                                 methodHandle method,
+                                 Register obj_reg,
+                                 Register result) {
+  Label slowCase;
+
+  // Unlike for Object.hashCode, System.identityHashCode is static method and
+  // gets object as argument instead of the receiver.
+  if (method->intrinsic_id() == vmIntrinsics::_identityHashCode) {
+    Label Continue;
+    // return 0 for null reference input
+    __ cmpptr(obj_reg, (int32_t)NULL_WORD);
+    __ jcc(Assembler::notEqual, Continue);
+    __ xorptr(result, result);
+    __ ret(0);
+    __ bind(Continue);
+  }
+
+  __ movptr(result, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
+
+  // check if locked
+  __ testptr(result, markOopDesc::unlocked_value);
+  __ jcc(Assembler::zero, slowCase);
+
+  if (UseBiasedLocking) {
+    // Check if biased and fall through to runtime if so
+    __ testptr(result, markOopDesc::biased_lock_bit_in_place);
+    __ jcc(Assembler::notZero, slowCase);
+  }
+
+  // get hash
+#ifdef _LP64
+  // Read the header and build a mask to get its hash field.
+  // Depend on hash_mask being at most 32 bits and avoid the use of hash_mask_in_place
+  // because it could be larger than 32 bits in a 64-bit vm. See markOop.hpp.
+  __ shrptr(result, markOopDesc::hash_shift);
+  __ andptr(result, markOopDesc::hash_mask);
+#else
+  __ andptr(result, markOopDesc::hash_mask_in_place);
+#endif //_LP64
+
+  // test if hashCode exists
+  __ jcc(Assembler::zero, slowCase);
+#ifndef _LP64
+  __ shrptr(result, markOopDesc::hash_shift);
+#endif
+  __ ret(0);
+  __ bind(slowCase);
+}
+#endif //COMPILER1
+
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1754,34 +1754,10 @@
   int vep_offset = ((intptr_t)__ pc()) - start;
 
 #ifdef COMPILER1
-  if (InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) {
-    // Object.hashCode can pull the hashCode from the header word
-    // instead of doing a full VM transition once it's been computed.
-    // Since hashCode is usually polymorphic at call sites we can't do
-    // this optimization at the call site without a lot of work.
-    Label slowCase;
-    Register receiver = rcx;
-    Register result = rax;
-    __ movptr(result, Address(receiver, oopDesc::mark_offset_in_bytes()));
-
-    // check if locked
-    __ testptr(result, markOopDesc::unlocked_value);
-    __ jcc (Assembler::zero, slowCase);
-
-    if (UseBiasedLocking) {
-      // Check if biased and fall through to runtime if so
-      __ testptr(result, markOopDesc::biased_lock_bit_in_place);
-      __ jcc (Assembler::notZero, slowCase);
-    }
-
-    // get hash
-    __ andptr(result, markOopDesc::hash_mask_in_place);
-    // test if hashCode exists
-    __ jcc  (Assembler::zero, slowCase);
-    __ shrptr(result, markOopDesc::hash_shift);
-    __ ret(0);
-    __ bind (slowCase);
-  }
+  // For Object.hashCode, System.identityHashCode try to pull hashCode from object header if available.
+  if ((InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) || (method->intrinsic_id() == vmIntrinsics::_identityHashCode)) {
+    inline_check_hashcode_from_object_header(masm, method, rcx /*obj_reg*/, rax /*result*/);
+   }
 #endif // COMPILER1
 
   // The instruction at the verified entry point must be 5 bytes or longer
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -2058,6 +2058,13 @@
 
   int vep_offset = ((intptr_t)__ pc()) - start;
 
+#ifdef COMPILER1
+  // For Object.hashCode, System.identityHashCode try to pull hashCode from object header if available.
+  if ((InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) || (method->intrinsic_id() == vmIntrinsics::_identityHashCode)) {
+    inline_check_hashcode_from_object_header(masm, method, j_rarg0 /*obj_reg*/, rax /*result*/);
+  }
+#endif // COMPILER1
+
   // The instruction at the verified entry point must be 5 bytes or longer
   // because it can be patched on the fly by make_non_entrant. The stack bang
   // instruction fits that requirement.
--- a/hotspot/src/cpu/zero/vm/globals_zero.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -32,7 +32,6 @@
 // Set the default values for platform dependent flags used by the
 // runtime system.  See globals.hpp for details of what they do.
 
-define_pd_global(bool,  ConvertSleepToYield,  true);
 define_pd_global(bool,  ShareVtableStubs,     true);
 define_pd_global(bool,  NeedsDeoptSuspend,    false);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/G1HeapRegionType.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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 sun.jvm.hotspot.gc.shared;
+
+//These definitions should be kept in sync with the definitions in the HotSpot code.
+
+public enum G1HeapRegionType {
+  Free ("Free"),
+  Eden ("Eden"),
+  Survivor ("Survivor"),
+  StartsHumongous ("Starts Humongous"),
+  ContinuesHumongous ("Continues Humongous"),
+  Old ("Old"),
+  Archive ("Archive"),
+  G1HeapRegionTypeEndSentinel ("G1HeapRegionTypeEndSentinel");
+
+  private final String value;
+
+  G1HeapRegionType(String val) {
+    this.value = val;
+  }
+  public String value() {
+    return value;
+  }
+}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java	Wed Jul 05 21:24:14 2017 +0200
@@ -70,56 +70,64 @@
     public static final Register r28 = new Register(28, 28, "r28", CPU);
     public static final Register r29 = new Register(29, 29, "r29", CPU);
     public static final Register r30 = new Register(30, 30, "r30", CPU);
+
+    /*
+     * r31 is not a general purpose register, but represents either the stackpointer or the
+     * zero/discard register depending on the instruction. So we represent those two uses as two
+     * different registers. The register numbers are kept in sync with register_aarch64.hpp and have
+     * to be sequential, hence we also need a general r31 register here, which is never used.
+     */
     public static final Register r31 = new Register(31, 31, "r31", CPU);
+    public static final Register zr = new Register(32, 31, "zr", CPU);
+    public static final Register sp = new Register(33, 31, "sp", CPU);
 
     public static final Register lr = r30;
-    public static final Register zr = r31;
-    public static final Register sp = r31;
 
     // @formatter:off
     public static final Register[] cpuRegisters = {
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
         r8,  r9,  r10, r11, r12, r13, r14, r15,
         r16, r17, r18, r19, r20, r21, r22, r23,
-        r24, r25, r26, r27, r28, r29, r30, r31
+        r24, r25, r26, r27, r28, r29, r30, r31,
+        zr,  sp
     };
     // @formatter:on
 
     public static final RegisterCategory SIMD = new RegisterCategory("SIMD");
 
     // Simd registers
-    public static final Register v0 = new Register(32, 0, "v0", SIMD);
-    public static final Register v1 = new Register(33, 1, "v1", SIMD);
-    public static final Register v2 = new Register(34, 2, "v2", SIMD);
-    public static final Register v3 = new Register(35, 3, "v3", SIMD);
-    public static final Register v4 = new Register(36, 4, "v4", SIMD);
-    public static final Register v5 = new Register(37, 5, "v5", SIMD);
-    public static final Register v6 = new Register(38, 6, "v6", SIMD);
-    public static final Register v7 = new Register(39, 7, "v7", SIMD);
-    public static final Register v8 = new Register(40, 8, "v8", SIMD);
-    public static final Register v9 = new Register(41, 9, "v9", SIMD);
-    public static final Register v10 = new Register(42, 10, "v10", SIMD);
-    public static final Register v11 = new Register(43, 11, "v11", SIMD);
-    public static final Register v12 = new Register(44, 12, "v12", SIMD);
-    public static final Register v13 = new Register(45, 13, "v13", SIMD);
-    public static final Register v14 = new Register(46, 14, "v14", SIMD);
-    public static final Register v15 = new Register(47, 15, "v15", SIMD);
-    public static final Register v16 = new Register(48, 16, "v16", SIMD);
-    public static final Register v17 = new Register(49, 17, "v17", SIMD);
-    public static final Register v18 = new Register(50, 18, "v18", SIMD);
-    public static final Register v19 = new Register(51, 19, "v19", SIMD);
-    public static final Register v20 = new Register(52, 20, "v20", SIMD);
-    public static final Register v21 = new Register(53, 21, "v21", SIMD);
-    public static final Register v22 = new Register(54, 22, "v22", SIMD);
-    public static final Register v23 = new Register(55, 23, "v23", SIMD);
-    public static final Register v24 = new Register(56, 24, "v24", SIMD);
-    public static final Register v25 = new Register(57, 25, "v25", SIMD);
-    public static final Register v26 = new Register(58, 26, "v26", SIMD);
-    public static final Register v27 = new Register(59, 27, "v27", SIMD);
-    public static final Register v28 = new Register(60, 28, "v28", SIMD);
-    public static final Register v29 = new Register(61, 29, "v29", SIMD);
-    public static final Register v30 = new Register(62, 30, "v30", SIMD);
-    public static final Register v31 = new Register(63, 31, "v31", SIMD);
+    public static final Register v0 = new Register(34, 0, "v0", SIMD);
+    public static final Register v1 = new Register(35, 1, "v1", SIMD);
+    public static final Register v2 = new Register(36, 2, "v2", SIMD);
+    public static final Register v3 = new Register(37, 3, "v3", SIMD);
+    public static final Register v4 = new Register(38, 4, "v4", SIMD);
+    public static final Register v5 = new Register(39, 5, "v5", SIMD);
+    public static final Register v6 = new Register(40, 6, "v6", SIMD);
+    public static final Register v7 = new Register(41, 7, "v7", SIMD);
+    public static final Register v8 = new Register(42, 8, "v8", SIMD);
+    public static final Register v9 = new Register(43, 9, "v9", SIMD);
+    public static final Register v10 = new Register(44, 10, "v10", SIMD);
+    public static final Register v11 = new Register(45, 11, "v11", SIMD);
+    public static final Register v12 = new Register(46, 12, "v12", SIMD);
+    public static final Register v13 = new Register(47, 13, "v13", SIMD);
+    public static final Register v14 = new Register(48, 14, "v14", SIMD);
+    public static final Register v15 = new Register(49, 15, "v15", SIMD);
+    public static final Register v16 = new Register(50, 16, "v16", SIMD);
+    public static final Register v17 = new Register(51, 17, "v17", SIMD);
+    public static final Register v18 = new Register(52, 18, "v18", SIMD);
+    public static final Register v19 = new Register(53, 19, "v19", SIMD);
+    public static final Register v20 = new Register(54, 20, "v20", SIMD);
+    public static final Register v21 = new Register(55, 21, "v21", SIMD);
+    public static final Register v22 = new Register(56, 22, "v22", SIMD);
+    public static final Register v23 = new Register(57, 23, "v23", SIMD);
+    public static final Register v24 = new Register(58, 24, "v24", SIMD);
+    public static final Register v25 = new Register(59, 25, "v25", SIMD);
+    public static final Register v26 = new Register(60, 26, "v26", SIMD);
+    public static final Register v27 = new Register(61, 27, "v27", SIMD);
+    public static final Register v28 = new Register(62, 28, "v28", SIMD);
+    public static final Register v29 = new Register(63, 29, "v29", SIMD);
+    public static final Register v30 = new Register(64, 30, "v30", SIMD);
+    public static final Register v31 = new Register(65, 31, "v31", SIMD);
 
     // @formatter:off
     public static final Register[] simdRegisters = {
@@ -136,6 +144,7 @@
         r8,  r9,  r10, r11, r12, r13, r14, r15,
         r16, r17, r18, r19, r20, r21, r22, r23,
         r24, r25, r26, r27, r28, r29, r30, r31,
+        zr,  sp,
 
         v0,  v1,  v2,  v3,  v4,  v5,  v6,  v7,
         v8,  v9,  v10, v11, v12, v13, v14, v15,
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java	Wed Jul 05 21:24:14 2017 +0200
@@ -31,6 +31,7 @@
 import static jdk.vm.ci.aarch64.AArch64.r28;
 import static jdk.vm.ci.aarch64.AArch64.r29;
 import static jdk.vm.ci.aarch64.AArch64.r3;
+import static jdk.vm.ci.aarch64.AArch64.r31;
 import static jdk.vm.ci.aarch64.AArch64.r4;
 import static jdk.vm.ci.aarch64.AArch64.r5;
 import static jdk.vm.ci.aarch64.AArch64.r6;
@@ -45,11 +46,13 @@
 import static jdk.vm.ci.aarch64.AArch64.v5;
 import static jdk.vm.ci.aarch64.AArch64.v6;
 import static jdk.vm.ci.aarch64.AArch64.v7;
+import static jdk.vm.ci.aarch64.AArch64.zr;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import jdk.vm.ci.aarch64.AArch64;
@@ -130,16 +133,20 @@
     public static final Register threadRegister = r28;
     public static final Register fp = r29;
 
+    private static final Register[] reservedRegisters = {threadRegister, fp, lr, r31, zr, sp};
+
     private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
         Register[] allRegisters = arch.getAvailableValueRegisters();
-        Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 5 : 4)];
+        Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
+        List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
 
         int idx = 0;
         for (Register reg : allRegisters) {
-            if (reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(sp)) {
-                // skip thread register, frame pointer, link register and stack pointer
+            if (reservedRegistersList.contains(reg)) {
+                // skip reserved registers
                 continue;
             }
+            assert !(reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(r31) || reg.equals(zr) || reg.equals(sp));
             if (reserveForHeapBase && reg.equals(heapBaseRegister)) {
                 // skip heap base register
                 continue;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Wed Jul 05 21:24:14 2017 +0200
@@ -45,6 +45,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import jdk.vm.ci.code.Architecture;
@@ -119,14 +120,17 @@
      */
     private final boolean needsNativeStackHomeSpace;
 
+    private static final Register[] reservedRegisters = {rsp, r15};
+
     private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
         Register[] allRegisters = arch.getAvailableValueRegisters();
-        Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 3 : 2)];
+        Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
+        List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
 
         int idx = 0;
         for (Register reg : allRegisters) {
-            if (reg.equals(rsp) || reg.equals(r15)) {
-                // skip stack pointer and thread register
+            if (reservedRegistersList.contains(reg)) {
+                // skip reserved registers
                 continue;
             }
             if (reserveForHeapBase && reg.equals(r12)) {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Wed Jul 05 21:24:14 2017 +0200
@@ -68,6 +68,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.CallingConvention;
@@ -140,14 +141,17 @@
                     i0, i1, i2, i3, i4, i5, i6, i7};
     // @formatter:on
 
+    private static final Register[] reservedRegisters = {sp, g0, g2};
+
     private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
         Register[] allRegisters = arch.getAvailableValueRegisters();
-        Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 4 : 3)];
+        Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
+        List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
 
         int idx = 0;
         for (Register reg : allRegisters) {
-            if (reg.equals(sp) || reg.equals(g2) || reg.equals(g0)) {
-                // skip g0, stack pointer and thread register
+            if (reservedRegistersList.contains(reg)) {
+                // skip reserved registers
                 continue;
             }
             if (reserveForHeapBase && reg.equals(g6)) {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java	Wed Jul 05 21:24:14 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
@@ -26,6 +26,7 @@
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
 
 import java.lang.reflect.Array;
+import java.util.Objects;
 
 import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
@@ -70,13 +71,13 @@
         } else if (x instanceof HotSpotObjectConstantImpl) {
             return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object();
         } else {
-            return x.equals(y);
+            return Objects.equals(x, y);
         }
     }
 
     @Override
     public Integer readArrayLength(JavaConstant array) {
-        if (array.getJavaKind() != JavaKind.Object || array.isNull()) {
+        if (array == null || array.getJavaKind() != JavaKind.Object || array.isNull()) {
             return null;
         }
 
@@ -133,12 +134,12 @@
 
     @Override
     public JavaConstant readArrayElement(JavaConstant array, int index) {
-        if (array.getJavaKind() != JavaKind.Object || array.isNull()) {
+        if (array == null || array.getJavaKind() != JavaKind.Object || array.isNull()) {
             return null;
         }
         Object a = ((HotSpotObjectConstantImpl) array).object();
 
-        if (index < 0 || index >= Array.getLength(a)) {
+        if (!a.getClass().isArray() || index < 0 || index >= Array.getLength(a)) {
             return null;
         }
 
@@ -184,7 +185,7 @@
 
     @Override
     public JavaConstant boxPrimitive(JavaConstant source) {
-        if (!source.getJavaKind().isPrimitive() || !isBoxCached(source)) {
+        if (source == null || !source.getJavaKind().isPrimitive() || !isBoxCached(source)) {
             return null;
         }
         return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive());
@@ -192,7 +193,7 @@
 
     @Override
     public JavaConstant unboxPrimitive(JavaConstant source) {
-        if (!source.getJavaKind().isObject()) {
+        if (source == null || !source.getJavaKind().isObject()) {
             return null;
         }
         if (source.isNull()) {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java	Wed Jul 05 21:24:14 2017 +0200
@@ -57,6 +57,13 @@
     boolean isDontInline();
 
     /**
+     * Returns true if this method has a {@code ReservedStackAccess} annotation.
+     *
+     * @return true if ReservedStackAccess annotation present, false otherwise
+     */
+    boolean hasReservedStackAccess();
+
+    /**
      * Manually adds a DontInline annotation to this method.
      */
     void setNotInlineable();
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -309,6 +309,15 @@
     }
 
     /**
+     * Returns true if this method has a {@code ReservedStackAccess} annotation.
+     *
+     * @return true if ReservedStackAccess annotation present, false otherwise
+     */
+    public boolean hasReservedStackAccess() {
+        return (getFlags() & config().methodFlagsReservedStackAccess) != 0;
+    }
+
+    /**
      * Manually adds a DontInline annotation to this method.
      */
     public void setNotInlineable() {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java	Wed Jul 05 21:24:14 2017 +0200
@@ -850,6 +850,7 @@
     @HotSpotVMFlag(name = "DontCompileHugeMethods") @Stable public boolean dontCompileHugeMethods;
     @HotSpotVMFlag(name = "HugeMethodLimit") @Stable public int hugeMethodLimit;
     @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining;
+    @HotSpotVMFlag(name = "Inline") @Stable public boolean inline;
     @HotSpotVMFlag(name = "JVMCIUseFastLocking") @Stable public boolean useFastLocking;
     @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable;
     @HotSpotVMFlag(name = "CodeCacheSegmentSize") @Stable public int codeSegmentSize;
@@ -974,6 +975,7 @@
     @HotSpotVMFlag(name = "BlockZeroingLowLimit", archs = {"sparc"}) @Stable public int blockZeroingLowLimit;
 
     @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages;
+    @HotSpotVMFlag(name = "StackReservedPages") @Stable public int stackReservedPages;
     @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging;
     @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias;
     @HotSpotVMField(name = "CompilerToVM::Data::vm_page_size", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int vmPageSize;
@@ -1092,6 +1094,7 @@
     @HotSpotVMField(name = "JavaThread::_satb_mark_queue", type = "SATBMarkQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadSatbMarkQueueOffset;
     @HotSpotVMField(name = "JavaThread::_vm_result", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectResultOffset;
     @HotSpotVMField(name = "JavaThread::_jvmci_counters", type = "jlong*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciCountersThreadOffset;
+    @HotSpotVMField(name = "JavaThread::_reserved_stack_activation", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadReservedStackActivationOffset;
 
     /**
      * An invalid value for {@link #rtldDefault}.
@@ -1235,6 +1238,7 @@
     @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline;
     @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline;
     @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden;
+    @HotSpotVMConstant(name = "Method::_reserved_stack_access") @Stable public int methodFlagsReservedStackAccess;
     @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex;
     @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex;
 
@@ -1491,6 +1495,8 @@
     @HotSpotVMField(name = "StubRoutines::_updateBytesCRC32", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long updateBytesCRC32Stub;
     @HotSpotVMField(name = "StubRoutines::_crc_table_adr", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long crcTableAddress;
 
+    @HotSpotVMField(name = "StubRoutines::_throw_delayed_StackOverflowError_entry", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long throwDelayedStackOverflowErrorEntry;
+
     @HotSpotVMField(name = "StubRoutines::_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteArraycopy;
     @HotSpotVMField(name = "StubRoutines::_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortArraycopy;
     @HotSpotVMField(name = "StubRoutines::_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintArraycopy;
@@ -1548,6 +1554,7 @@
     @HotSpotVMAddress(name = "SharedRuntime::register_finalizer") @Stable public long registerFinalizerAddress;
     @HotSpotVMAddress(name = "SharedRuntime::exception_handler_for_return_address") @Stable public long exceptionHandlerForReturnAddressAddress;
     @HotSpotVMAddress(name = "SharedRuntime::OSR_migration_end") @Stable public long osrMigrationEndAddress;
+    @HotSpotVMAddress(name = "SharedRuntime::enable_stack_reserved_zone") @Stable public long enableStackReservedZoneAddress;
 
     @HotSpotVMAddress(name = "os::javaTimeMillis") @Stable public long javaTimeMillisAddress;
     @HotSpotVMAddress(name = "os::javaTimeNanos") @Stable public long javaTimeNanosAddress;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.services/.checkstyle_checks.xml	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!--
+    Checkstyle-Configuration: Checks
+    Description: none
+-->
+<module name="Checker">
+  <property name="severity" value="error"/>
+  <module name="TreeWalker">
+    <property name="tabWidth" value="4"/>
+    <module name="FileContentsHolder"/>
+    <module name="JavadocStyle">
+      <property name="checkHtml" value="false"/>
+    </module>
+    <module name="LocalFinalVariableName"/>
+    <module name="LocalVariableName"/>
+    <module name="MemberName">
+      <property name="format" value="^(([a-z][a-zA-Z0-9]*$)|(_[A-Z][a-zA-Z0-9]*_[a-z][a-zA-Z0-9]*$))"/>
+    </module>
+    <module name="MethodName"/>
+    <module name="PackageName"/>
+    <module name="ParameterName"/>
+    <module name="TypeName">
+      <property name="format" value="^[A-Z][_a-zA-Z0-9]*$"/>
+    </module>
+    <module name="RedundantImport"/>
+    <module name="LineLength">
+      <property name="max" value="250"/>
+    </module>
+    <module name="MethodParamPad"/>
+    <module name="NoWhitespaceAfter">
+      <property name="tokens" value="ARRAY_INIT,BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS"/>
+    </module>
+    <module name="AvoidStarImport">
+       <property name="allowClassImports" value="false"/>
+       <property name="allowStaticMemberImports" value="false"/>
+    </module>
+    <module name="NoWhitespaceBefore">
+      <property name="tokens" value="SEMI,DOT,POST_DEC,POST_INC"/>
+    </module>
+    <module name="ParenPad"/>
+    <module name="TypecastParenPad">
+      <property name="tokens" value="RPAREN,TYPECAST"/>
+    </module>
+    <module name="WhitespaceAfter"/>
+    <module name="WhitespaceAround">
+      <property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAND,LE,LITERAL_ASSERT,LITERAL_CATCH,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_RETURN,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND"/>
+    </module>
+    <module name="RedundantModifier"/>
+    <module name="AvoidNestedBlocks">
+      <property name="allowInSwitchCase" value="true"/>
+    </module>
+    <module name="EmptyBlock">
+      <property name="option" value="text"/>
+      <property name="tokens" value="LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_IF,LITERAL_TRY,LITERAL_WHILE,STATIC_INIT"/>
+    </module>
+    <module name="LeftCurly"/>
+    <module name="NeedBraces"/>
+    <module name="RightCurly"/>
+    <module name="EmptyStatement"/>
+    <module name="HiddenField">
+      <property name="severity" value="ignore"/>
+      <property name="ignoreConstructorParameter" value="true"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="FinalClass"/>
+    <module name="HideUtilityClassConstructor">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="ArrayTypeStyle"/>
+    <module name="UpperEll"/>
+    <module name="FallThrough"/>
+    <module name="FinalLocalVariable">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="MultipleVariableDeclarations"/>
+    <module name="StringLiteralEquality">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="SuperFinalize"/>
+    <module name="UnnecessaryParentheses">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="Indentation">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="StaticVariableName">
+      <property name="format" value="^[A-Za-z][a-zA-Z0-9]*$"/>
+    </module>
+    <module name="EmptyForInitializerPad"/>
+    <module name="EmptyForIteratorPad"/>
+    <module name="ModifierOrder"/>
+    <module name="DefaultComesLast"/>
+    <module name="InnerAssignment">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="ModifiedControlVariable"/>
+    <module name="MutableException">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="ParameterAssignment">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <metadata name="net.sf.eclipsecs.core.comment" value="Illegal trailing whitespace(s) at the end of the line."/>
+      <property name="format" value="\s$"/>
+      <property name="message" value="Illegal trailing whitespace(s) at the end of the line."/>
+      <property name="ignoreComments" value="true"/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for trailing spaces at the end of a line"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <metadata name="net.sf.eclipsecs.core.comment" value="illegal space before a comma"/>
+      <property name="format" value=" ,"/>
+      <property name="message" value="illegal space before a comma"/>
+      <property name="ignoreComments" value="true"/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for whitespace before a comma."/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.customMessage" value="Illegal whitespace before a comma."/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="[^\x00-\x7F]"/>
+      <property name="message" value="Only use ASCII characters."/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="new (Hashtable|Vector|Stack|StringBuffer)[^\w]"/>
+      <property name="message" value="Don't use old synchronized collection classes"/>
+    </module>
+  </module>
+  <module name="RegexpHeader">
+    <property name="header" value="/\*\n \* Copyright \(c\) (20[0-9][0-9], )?20[0-9][0-9], Oracle and/or its affiliates. All rights reserved.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\).\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www.oracle.com if you need additional information or have any\n \* questions.\n \*/\n"/>
+    <property name="fileExtensions" value="java"/>
+  </module>
+  <module name="FileTabCharacter">
+    <property name="severity" value="error"/>
+    <property name="fileExtensions" value="java"/>
+  </module>
+  <module name="NewlineAtEndOfFile">
+    <property name="lineSeparator" value="lf"/>
+  </module>
+  <module name="Translation"/>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop constant name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume constant name check"/>
+    <property name="checkFormat" value="ConstantNameCheck"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Allow non-conforming constant names"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop method name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume method name check"/>
+    <property name="checkFormat" value="MethodName"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable method name checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop parameter assignment check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume parameter assignment check"/>
+    <property name="checkFormat" value="ParameterAssignment"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable Parameter Assignment"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop final variable check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume final variable check"/>
+    <property name="checkFormat" value="FinalLocalVariable"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable final variable checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop"/>
+    <property name="onCommentFormat" value="Checkstyle: resume"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable all checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop inner assignment check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume inner assignment check"/>
+    <property name="checkFormat" value="InnerAssignment"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable inner assignment checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop field name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume field name check"/>
+    <property name="checkFormat" value="MemberName"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable field name checks"/>
+  </module>
+  <module name="RegexpMultiline">
+    <metadata name="net.sf.eclipsecs.core.comment" value="illegal Windows line ending"/>
+    <property name="format" value="\r\n"/>
+    <property name="message" value="illegal Windows line ending"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop header check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume header check"/>
+    <property name="checkFormat" value=".*Header"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable header checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop line length check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume line length check"/>
+    <property name="checkFormat" value="LineLength"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: start generated"/>
+    <property name="onCommentFormat" value="CheckStyle: stop generated"/>
+    <property name="checkFormat" value=".*Name|.*LineLength|.*Header"/>
+  </module>
+</module>
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp	Wed Jul 05 21:24:14 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
@@ -4042,61 +4042,6 @@
 //        could have been signaled after a wait started
 //    1 : signaled - thread is running or ready
 //
-// Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can
-// hang indefinitely.  For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable.
-// For specifics regarding the bug see GLIBC BUGID 261237 :
-//    http://www.mail-archive.com/debian-glibc@lists.debian.org/msg10837.html.
-// Briefly, pthread_cond_timedwait() calls with an expiry time that's not in the future
-// will either hang or corrupt the condvar, resulting in subsequent hangs if the condvar
-// is used.  (The simple C test-case provided in the GLIBC bug report manifests the
-// hang).  The JVM is vulernable via sleep(), Object.wait(timo), LockSupport.parkNanos()
-// and monitorenter when we're using 1-0 locking.  All those operations may result in
-// calls to pthread_cond_timedwait().  Using LD_ASSUME_KERNEL to use an older version
-// of libpthread avoids the problem, but isn't practical.
-//
-// Possible remedies:
-//
-// 1.   Establish a minimum relative wait time.  50 to 100 msecs seems to work.
-//      This is palliative and probabilistic, however.  If the thread is preempted
-//      between the call to compute_abstime() and pthread_cond_timedwait(), more
-//      than the minimum period may have passed, and the abstime may be stale (in the
-//      past) resultin in a hang.   Using this technique reduces the odds of a hang
-//      but the JVM is still vulnerable, particularly on heavily loaded systems.
-//
-// 2.   Modify park-unpark to use per-thread (per ParkEvent) pipe-pairs instead
-//      of the usual flag-condvar-mutex idiom.  The write side of the pipe is set
-//      NDELAY. unpark() reduces to write(), park() reduces to read() and park(timo)
-//      reduces to poll()+read().  This works well, but consumes 2 FDs per extant
-//      thread.
-//
-// 3.   Embargo pthread_cond_timedwait() and implement a native "chron" thread
-//      that manages timeouts.  We'd emulate pthread_cond_timedwait() by enqueuing
-//      a timeout request to the chron thread and then blocking via pthread_cond_wait().
-//      This also works well.  In fact it avoids kernel-level scalability impediments
-//      on certain platforms that don't handle lots of active pthread_cond_timedwait()
-//      timers in a graceful fashion.
-//
-// 4.   When the abstime value is in the past it appears that control returns
-//      correctly from pthread_cond_timedwait(), but the condvar is left corrupt.
-//      Subsequent timedwait/wait calls may hang indefinitely.  Given that, we
-//      can avoid the problem by reinitializing the condvar -- by cond_destroy()
-//      followed by cond_init() -- after all calls to pthread_cond_timedwait().
-//      It may be possible to avoid reinitialization by checking the return
-//      value from pthread_cond_timedwait().  In addition to reinitializing the
-//      condvar we must establish the invariant that cond_signal() is only called
-//      within critical sections protected by the adjunct mutex.  This prevents
-//      cond_signal() from "seeing" a condvar that's in the midst of being
-//      reinitialized or that is corrupt.  Sadly, this invariant obviates the
-//      desirable signal-after-unlock optimization that avoids futile context switching.
-//
-//      I'm also concerned that some versions of NTPL might allocate an auxilliary
-//      structure when a condvar is used or initialized.  cond_destroy()  would
-//      release the helper structure.  Our reinitialize-after-timedwait fix
-//      put excessive stress on malloc/free and locks protecting the c-heap.
-//
-// We currently use (4).  See the WorkAroundNTPLTimedWaitHang flag.
-// It may be possible to refine (4) by checking the kernel and NTPL verisons
-// and only enabling the work-around for vulnerable environments.
 
 // utility to compute the abstime argument to timedwait:
 // millis is the relative timeout time
@@ -4208,10 +4153,6 @@
 
   while (_Event < 0) {
     status = pthread_cond_timedwait(_cond, _mutex, &abst);
-    if (status != 0 && WorkAroundNPTLTimedWaitHang) {
-      pthread_cond_destroy(_cond);
-      pthread_cond_init(_cond, NULL);
-    }
     assert_status(status == 0 || status == EINTR ||
                   status == ETIMEDOUT,
                   status, "cond_timedwait");
@@ -4255,10 +4196,6 @@
   assert_status(status == 0, status, "mutex_lock");
   int AnyWaiters = _nParked;
   assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
-  if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
-    AnyWaiters = 0;
-    pthread_cond_signal(_cond);
-  }
   status = pthread_mutex_unlock(_mutex);
   assert_status(status == 0, status, "mutex_unlock");
   if (AnyWaiters != 0) {
@@ -4391,7 +4328,7 @@
   if (_counter > 0)  { // no wait needed
     _counter = 0;
     status = pthread_mutex_unlock(_mutex);
-    assert(status == 0, "invariant");
+    assert_status(status == 0, status, "invariant");
     // Paranoia to ensure our locked and lock-free paths interact
     // correctly with each other and Java-level accesses.
     OrderAccess::fence();
@@ -4414,10 +4351,6 @@
     status = pthread_cond_wait(_cond, _mutex);
   } else {
     status = pthread_cond_timedwait(_cond, _mutex, &absTime);
-    if (status != 0 && WorkAroundNPTLTimedWaitHang) {
-      pthread_cond_destroy(_cond);
-      pthread_cond_init(_cond, NULL);
-    }
   }
   assert_status(status == 0 || status == EINTR ||
                 status == ETIMEDOUT,
@@ -4442,24 +4375,14 @@
 
 void Parker::unpark() {
   int status = pthread_mutex_lock(_mutex);
-  assert(status == 0, "invariant");
+  assert_status(status == 0, status, "invariant");
   const int s = _counter;
   _counter = 1;
+  status = pthread_mutex_unlock(_mutex);
+  assert_status(status == 0, status, "invariant");
   if (s < 1) {
-    if (WorkAroundNPTLTimedWaitHang) {
-      status = pthread_cond_signal(_cond);
-      assert(status == 0, "invariant");
-      status = pthread_mutex_unlock(_mutex);
-      assert(status == 0, "invariant");
-    } else {
-      status = pthread_mutex_unlock(_mutex);
-      assert(status == 0, "invariant");
-      status = pthread_cond_signal(_cond);
-      assert(status == 0, "invariant");
-    }
-  } else {
-    pthread_mutex_unlock(_mutex);
-    assert(status == 0, "invariant");
+    status = pthread_cond_signal(_cond);
+    assert_status(status == 0, status, "invariant");
   }
 }
 
--- a/hotspot/src/os/linux/vm/os_linux.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/os/linux/vm/os_linux.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -4771,6 +4771,25 @@
   }
 }
 
+// older glibc versions don't have this macro (which expands to
+// an optimized bit-counting function) so we have to roll our own
+#ifndef CPU_COUNT
+
+static int _cpu_count(const cpu_set_t* cpus) {
+  int count = 0;
+  // only look up to the number of configured processors
+  for (int i = 0; i < os::processor_count(); i++) {
+    if (CPU_ISSET(i, cpus)) {
+      count++;
+    }
+  }
+  return count;
+}
+
+#define CPU_COUNT(cpus) _cpu_count(cpus)
+
+#endif // CPU_COUNT
+
 // Get the current number of available processors for this process.
 // This value can change at any time during a process's lifetime.
 // sched_getaffinity gives an accurate answer as it accounts for cpusets.
@@ -4786,6 +4805,9 @@
   int configured_cpus = processor_count();  // upper bound on available cpus
   int cpu_count = 0;
 
+// old build platforms may not support dynamic cpu sets
+#ifdef CPU_ALLOC
+
   // To enable easy testing of the dynamic path on different platforms we
   // introduce a diagnostic flag: UseCpuAllocPath
   if (configured_cpus >= CPU_SETSIZE || UseCpuAllocPath) {
@@ -4814,10 +4836,18 @@
     log_trace(os)("active_processor_count: using static path - configured processors: %d",
                   configured_cpus);
   }
+#else // CPU_ALLOC
+// these stubs won't be executed
+#define CPU_COUNT_S(size, cpus) -1
+#define CPU_FREE(cpus)
+
+  log_trace(os)("active_processor_count: only static path available - configured processors: %d",
+                configured_cpus);
+#endif // CPU_ALLOC
 
   // pid 0 means the current thread - which we have to assume represents the process
   if (sched_getaffinity(0, cpus_size, cpus_p) == 0) {
-    if (cpus_p != &cpus) {
+    if (cpus_p != &cpus) { // can only be true when CPU_ALLOC used
       cpu_count = CPU_COUNT_S(cpus_size, cpus_p);
     }
     else {
@@ -4831,7 +4861,7 @@
             "which may exceed available processors", strerror(errno), cpu_count);
   }
 
-  if (cpus_p != &cpus) {
+  if (cpus_p != &cpus) { // can only be true when CPU_ALLOC used
     CPU_FREE(cpus_p);
   }
 
@@ -5349,61 +5379,6 @@
 //        could have been signaled after a wait started
 //    1 : signaled - thread is running or ready
 //
-// Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can
-// hang indefinitely.  For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable.
-// For specifics regarding the bug see GLIBC BUGID 261237 :
-//    http://www.mail-archive.com/debian-glibc@lists.debian.org/msg10837.html.
-// Briefly, pthread_cond_timedwait() calls with an expiry time that's not in the future
-// will either hang or corrupt the condvar, resulting in subsequent hangs if the condvar
-// is used.  (The simple C test-case provided in the GLIBC bug report manifests the
-// hang).  The JVM is vulernable via sleep(), Object.wait(timo), LockSupport.parkNanos()
-// and monitorenter when we're using 1-0 locking.  All those operations may result in
-// calls to pthread_cond_timedwait().  Using LD_ASSUME_KERNEL to use an older version
-// of libpthread avoids the problem, but isn't practical.
-//
-// Possible remedies:
-//
-// 1.   Establish a minimum relative wait time.  50 to 100 msecs seems to work.
-//      This is palliative and probabilistic, however.  If the thread is preempted
-//      between the call to compute_abstime() and pthread_cond_timedwait(), more
-//      than the minimum period may have passed, and the abstime may be stale (in the
-//      past) resultin in a hang.   Using this technique reduces the odds of a hang
-//      but the JVM is still vulnerable, particularly on heavily loaded systems.
-//
-// 2.   Modify park-unpark to use per-thread (per ParkEvent) pipe-pairs instead
-//      of the usual flag-condvar-mutex idiom.  The write side of the pipe is set
-//      NDELAY. unpark() reduces to write(), park() reduces to read() and park(timo)
-//      reduces to poll()+read().  This works well, but consumes 2 FDs per extant
-//      thread.
-//
-// 3.   Embargo pthread_cond_timedwait() and implement a native "chron" thread
-//      that manages timeouts.  We'd emulate pthread_cond_timedwait() by enqueuing
-//      a timeout request to the chron thread and then blocking via pthread_cond_wait().
-//      This also works well.  In fact it avoids kernel-level scalability impediments
-//      on certain platforms that don't handle lots of active pthread_cond_timedwait()
-//      timers in a graceful fashion.
-//
-// 4.   When the abstime value is in the past it appears that control returns
-//      correctly from pthread_cond_timedwait(), but the condvar is left corrupt.
-//      Subsequent timedwait/wait calls may hang indefinitely.  Given that, we
-//      can avoid the problem by reinitializing the condvar -- by cond_destroy()
-//      followed by cond_init() -- after all calls to pthread_cond_timedwait().
-//      It may be possible to avoid reinitialization by checking the return
-//      value from pthread_cond_timedwait().  In addition to reinitializing the
-//      condvar we must establish the invariant that cond_signal() is only called
-//      within critical sections protected by the adjunct mutex.  This prevents
-//      cond_signal() from "seeing" a condvar that's in the midst of being
-//      reinitialized or that is corrupt.  Sadly, this invariant obviates the
-//      desirable signal-after-unlock optimization that avoids futile context switching.
-//
-//      I'm also concerned that some versions of NTPL might allocate an auxilliary
-//      structure when a condvar is used or initialized.  cond_destroy()  would
-//      release the helper structure.  Our reinitialize-after-timedwait fix
-//      put excessive stress on malloc/free and locks protecting the c-heap.
-//
-// We currently use (4).  See the WorkAroundNTPLTimedWaitHang flag.
-// It may be possible to refine (4) by checking the kernel and NTPL verisons
-// and only enabling the work-around for vulnerable environments.
 
 // utility to compute the abstime argument to timedwait:
 // millis is the relative timeout time
@@ -5529,10 +5504,6 @@
 
   while (_Event < 0) {
     status = pthread_cond_timedwait(_cond, _mutex, &abst);
-    if (status != 0 && WorkAroundNPTLTimedWaitHang) {
-      pthread_cond_destroy(_cond);
-      pthread_cond_init(_cond, os::Linux::condAttr());
-    }
     assert_status(status == 0 || status == EINTR ||
                   status == ETIME || status == ETIMEDOUT,
                   status, "cond_timedwait");
@@ -5576,10 +5547,6 @@
   assert_status(status == 0, status, "mutex_lock");
   int AnyWaiters = _nParked;
   assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
-  if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
-    AnyWaiters = 0;
-    pthread_cond_signal(_cond);
-  }
   status = pthread_mutex_unlock(_mutex);
   assert_status(status == 0, status, "mutex_unlock");
   if (AnyWaiters != 0) {
@@ -5731,7 +5698,7 @@
   if (_counter > 0)  { // no wait needed
     _counter = 0;
     status = pthread_mutex_unlock(_mutex);
-    assert(status == 0, "invariant");
+    assert_status(status == 0, status, "invariant");
     // Paranoia to ensure our locked and lock-free paths interact
     // correctly with each other and Java-level accesses.
     OrderAccess::fence();
@@ -5757,10 +5724,6 @@
   } else {
     _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
     status = pthread_cond_timedwait(&_cond[_cur_index], _mutex, &absTime);
-    if (status != 0 && WorkAroundNPTLTimedWaitHang) {
-      pthread_cond_destroy(&_cond[_cur_index]);
-      pthread_cond_init(&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());
-    }
   }
   _cur_index = -1;
   assert_status(status == 0 || status == EINTR ||
@@ -5786,33 +5749,17 @@
 
 void Parker::unpark() {
   int status = pthread_mutex_lock(_mutex);
-  assert(status == 0, "invariant");
+  assert_status(status == 0, status, "invariant");
   const int s = _counter;
   _counter = 1;
-  if (s < 1) {
-    // thread might be parked
-    if (_cur_index != -1) {
-      // thread is definitely parked
-      if (WorkAroundNPTLTimedWaitHang) {
-        status = pthread_cond_signal(&_cond[_cur_index]);
-        assert(status == 0, "invariant");
-        status = pthread_mutex_unlock(_mutex);
-        assert(status == 0, "invariant");
-      } else {
-        // must capture correct index before unlocking
-        int index = _cur_index;
-        status = pthread_mutex_unlock(_mutex);
-        assert(status == 0, "invariant");
-        status = pthread_cond_signal(&_cond[index]);
-        assert(status == 0, "invariant");
-      }
-    } else {
-      pthread_mutex_unlock(_mutex);
-      assert(status == 0, "invariant");
-    }
-  } else {
-    pthread_mutex_unlock(_mutex);
-    assert(status == 0, "invariant");
+  // must capture correct index before unlocking
+  int index = _cur_index;
+  status = pthread_mutex_unlock(_mutex);
+  assert_status(status == 0, status, "invariant");
+  if (s < 1 && index != -1) {
+    // thread is definitely parked
+    status = pthread_cond_signal(&_cond[index]);
+    assert_status(status == 0, status, "invariant");
   }
 }
 
--- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -246,7 +246,6 @@
 bool PICL::open_library() {
   _dl_handle = dlopen("libpicl.so.1", RTLD_LAZY);
   if (_dl_handle == NULL) {
-    warning("PICL (libpicl.so.1) is missing. Performance will not be optimal.");
     return false;
   }
   if (!bind_library_functions()) {
--- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -730,7 +730,7 @@
     }
   } else if (rt == objectNull &&
            (l->as_NewInstance() || l->as_NewArray() ||
-             (UseNewCode && l->as_Local() && l->as_Local()->is_receiver()))) {
+             (l->as_Local() && l->as_Local()->is_receiver()))) {
     if (x->cond() == Instruction::eql) {
       BlockBegin* sux = x->fsux();
       set_canonical(new Goto(sux, x->state_before(), is_safepoint(x, sux)));
--- a/hotspot/src/share/vm/ci/ciField.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/ci/ciField.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -211,6 +211,12 @@
   // so there is no hacking of finals going on with them.
   if (holder->is_anonymous())
     return true;
+  // Trust final fields in all boxed classes
+  if (holder->is_box_klass())
+    return true;
+  // Trust final fields in String
+  if (holder->name() == ciSymbol::java_lang_String())
+    return true;
   // Trust Atomic*FieldUpdaters: they are very important for performance, and make up one
   // more reason not to use Unsafe, if their final fields are trusted. See more in JDK-8140483.
   if (holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl() ||
--- a/hotspot/src/share/vm/code/codeBlob.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/code/codeBlob.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -291,6 +291,9 @@
   {
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     blob = new (size) MethodHandlesAdapterBlob(size);
+    if (blob == NULL) {
+      vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CodeCache: no room for method handle adapter blob");
+    }
   }
   // Track memory usage statistic after releasing CodeCache_lock
   MemoryService::track_code_cache_memory_usage();
--- a/hotspot/src/share/vm/code/nmethod.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/code/nmethod.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -33,6 +33,7 @@
 #include "compiler/compileBroker.hpp"
 #include "compiler/compileLog.hpp"
 #include "compiler/compilerDirectives.hpp"
+#include "compiler/directivesParser.hpp"
 #include "compiler/disassembler.hpp"
 #include "interpreter/bytecode.hpp"
 #include "oops/methodData.hpp"
@@ -965,6 +966,12 @@
   }
 }
 
+void nmethod::maybe_print_nmethod(DirectiveSet* directive) {
+  bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption;
+  if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
+    print_nmethod(printnmethods);
+  }
+}
 
 void nmethod::print_nmethod(bool printmethod) {
   ttyLocker ttyl;  // keep the following output all in one block
--- a/hotspot/src/share/vm/code/nmethod.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/code/nmethod.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -29,6 +29,8 @@
 #include "code/pcDesc.hpp"
 #include "oops/metadata.hpp"
 
+class DirectiveSet;
+
 // This class is used internally by nmethods, to cache
 // exception/pc/handler information.
 
@@ -714,6 +716,8 @@
   void print_nul_chk_table()                      PRODUCT_RETURN;
   void print_recorded_oops()                      PRODUCT_RETURN;
   void print_recorded_metadata()                  PRODUCT_RETURN;
+
+  void maybe_print_nmethod(DirectiveSet* directive);
   void print_nmethod(bool print_code);
 
   // need to re-define this from CodeBlob else the overload hides it
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1919,12 +1919,9 @@
 
   collect_statistics(thread, time, task);
 
-  bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption;
-  if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
-    nmethod* nm = task->code();
-    if (nm != NULL) {
-      nm->print_nmethod(printnmethods);
-    }
+  nmethod* nm = task->code();
+  if (nm != NULL) {
+    nm->maybe_print_nmethod(directive);
   }
   DirectivesStack::release(directive);
 
--- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -2206,13 +2206,13 @@
     }
     if (res == 0) {
       LogHandle(gc, verify) log;
-      log.info("Livelock: no rank reduction!");
-      log.info(" Current:  addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n"
-               " Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n",
+      log.error("Livelock: no rank reduction!");
+      log.error(" Current:  addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n"
+                " Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n",
         p2i(addr),       res,        was_obj      ?"true":"false", was_live      ?"true":"false",
         p2i(_last_addr), _last_size, _last_was_obj?"true":"false", _last_was_live?"true":"false");
       ResourceMark rm;
-      _sp->print_on(log.info_stream());
+      _sp->print_on(log.error_stream());
       guarantee(false, "Verification failed.");
     }
     _last_addr = addr;
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -2224,8 +2224,8 @@
     if (!_marks->isMarked(addr)) {
       LogHandle(gc, verify) log;
       ResourceMark rm;
-      oop(addr)->print_on(log.info_stream());
-      log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
+      oop(addr)->print_on(log.error_stream());
+      log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
       _failed = true;
     }
     return true;
@@ -2350,9 +2350,9 @@
   verification_mark_bm()->iterate(&vcl);
   if (vcl.failed()) {
     LogHandle(gc, verify) log;
-    log.info("Verification failed");
+    log.error("Failed marking verification after remark");
     ResourceMark rm;
-    gch->print_on(log.info_stream());
+    gch->print_on(log.error_stream());
     fatal("CMS: failed marking verification after remark");
   }
 }
@@ -2923,7 +2923,7 @@
 
   CMSTokenSyncWithLocks ts(true, bitMapLock());
   GCTraceCPUTime tcpu;
-  CMSPhaseAccounting pa(this, "Concrurrent Mark");
+  CMSPhaseAccounting pa(this, "Concurrent Mark");
   bool res = markFromRootsWork();
   if (res) {
     _collectorState = Precleaning;
@@ -5880,8 +5880,8 @@
     if (!_cms_bm->isMarked(addr)) {
       LogHandle(gc, verify) log;
       ResourceMark rm;
-      oop(addr)->print_on(log.info_stream());
-      log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
+      oop(addr)->print_on(log.error_stream());
+      log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
       fatal("... aborting");
     }
   }
@@ -6661,8 +6661,8 @@
     if (!_cms_bm->isMarked(addr)) {
       LogHandle(gc, verify) log;
       ResourceMark rm;
-      oop(addr)->print_on(log.info_stream());
-      log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
+      oop(addr)->print_on(log.error_stream());
+      log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
       fatal("... aborting");
     }
 
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "classfile/classLoaderData.hpp"
 #include "gc/g1/concurrentMarkThread.inline.hpp"
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1CollectorPolicy.hpp"
@@ -123,6 +124,7 @@
     // wait until started is set.
     sleepBeforeNextCycle();
     if (_should_terminate) {
+      _cm->root_regions()->cancel_scan();
       break;
     }
 
@@ -132,6 +134,11 @@
       HandleMark   hm;
       double cycle_start = os::elapsedVTime();
 
+      {
+        GCConcPhaseTimer(_cm, "Concurrent Clearing of Claimed Marks");
+        ClassLoaderDataGraph::clear_claimed_marks();
+      }
+
       // We have to ensure that we finish scanning the root regions
       // before the next GC takes place. To ensure this we have to
       // make sure that we do not join the STS until the root regions
@@ -140,7 +147,7 @@
       // without the root regions have been scanned which would be a
       // correctness issue.
 
-      if (!cm()->has_aborted()) {
+      {
         GCConcPhaseTimer(_cm, "Concurrent Root Region Scanning");
         _cm->scanRootRegions();
       }
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1290,8 +1290,7 @@
       ref_processor_cm()->verify_no_references_recorded();
 
       // Abandon current iterations of concurrent marking and concurrent
-      // refinement, if any are in progress. We have to do this before
-      // wait_until_scan_finished() below.
+      // refinement, if any are in progress.
       concurrent_mark()->abort();
 
       // Make sure we'll choose a new allocation region afterwards.
@@ -2148,8 +2147,8 @@
   virtual bool doHeapRegion(HeapRegion* hr) {
     unsigned region_gc_time_stamp = hr->get_gc_time_stamp();
     if (_gc_time_stamp != region_gc_time_stamp) {
-      log_info(gc, verify)("Region " HR_FORMAT " has GC time stamp = %d, expected %d", HR_FORMAT_PARAMS(hr),
-                           region_gc_time_stamp, _gc_time_stamp);
+      log_error(gc, verify)("Region " HR_FORMAT " has GC time stamp = %d, expected %d", HR_FORMAT_PARAMS(hr),
+                            region_gc_time_stamp, _gc_time_stamp);
       _failures = true;
     }
     return false;
@@ -2848,7 +2847,7 @@
     (g1_policy()->young_list_target_length() * HeapRegion::GrainBytes) - survivor_used_bytes;
 
   VirtualSpaceSummary heap_summary = create_heap_space_summary();
-  return G1HeapSummary(heap_summary, used(), eden_used_bytes, eden_capacity_bytes, survivor_used_bytes);
+  return G1HeapSummary(heap_summary, used(), eden_used_bytes, eden_capacity_bytes, survivor_used_bytes, num_regions());
 }
 
 G1EvacSummary G1CollectedHeap::create_g1_evac_summary(G1EvacStats* stats) {
@@ -5186,8 +5185,8 @@
   NoYoungRegionsClosure() : _success(true) { }
   bool doHeapRegion(HeapRegion* r) {
     if (r->is_young()) {
-      log_info(gc, verify)("Region [" PTR_FORMAT ", " PTR_FORMAT ") tagged as young",
-                           p2i(r->bottom()), p2i(r->end()));
+      log_error(gc, verify)("Region [" PTR_FORMAT ", " PTR_FORMAT ") tagged as young",
+                            p2i(r->bottom()), p2i(r->end()));
       _success = false;
     }
     return false;
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -293,29 +293,83 @@
   _heap_alignment = MAX3(card_table_alignment, _space_alignment, page_size);
 }
 
-void G1CollectorPolicy::initialize_flags() {
-  if (G1HeapRegionSize != HeapRegion::GrainBytes) {
-    FLAG_SET_ERGO(size_t, G1HeapRegionSize, HeapRegion::GrainBytes);
+G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); }
+
+// There are three command line options related to the young gen size:
+// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is
+// just a short form for NewSize==MaxNewSize). G1 will use its internal
+// heuristics to calculate the actual young gen size, so these options
+// basically only limit the range within which G1 can pick a young gen
+// size. Also, these are general options taking byte sizes. G1 will
+// internally work with a number of regions instead. So, some rounding
+// will occur.
+//
+// If nothing related to the the young gen size is set on the command
+// line we should allow the young gen to be between G1NewSizePercent
+// and G1MaxNewSizePercent of the heap size. This means that every time
+// the heap size changes, the limits for the young gen size will be
+// recalculated.
+//
+// If only -XX:NewSize is set we should use the specified value as the
+// minimum size for young gen. Still using G1MaxNewSizePercent of the
+// heap as maximum.
+//
+// If only -XX:MaxNewSize is set we should use the specified value as the
+// maximum size for young gen. Still using G1NewSizePercent of the heap
+// as minimum.
+//
+// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values.
+// No updates when the heap size changes. There is a special case when
+// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a
+// different heuristic for calculating the collection set when we do mixed
+// collection.
+//
+// If only -XX:NewRatio is set we should use the specified ratio of the heap
+// as both min and max. This will be interpreted as "fixed" just like the
+// NewSize==MaxNewSize case above. But we will update the min and max
+// every time the heap size changes.
+//
+// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is
+// combined with either NewSize or MaxNewSize. (A warning message is printed.)
+class G1YoungGenSizer : public CHeapObj<mtGC> {
+private:
+  enum SizerKind {
+    SizerDefaults,
+    SizerNewSizeOnly,
+    SizerMaxNewSizeOnly,
+    SizerMaxAndNewSize,
+    SizerNewRatio
+  };
+  SizerKind _sizer_kind;
+  uint _min_desired_young_length;
+  uint _max_desired_young_length;
+  bool _adaptive_size;
+  uint calculate_default_min_length(uint new_number_of_heap_regions);
+  uint calculate_default_max_length(uint new_number_of_heap_regions);
+
+  // Update the given values for minimum and maximum young gen length in regions
+  // given the number of heap regions depending on the kind of sizing algorithm.
+  void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length);
+
+public:
+  G1YoungGenSizer();
+  // Calculate the maximum length of the young gen given the number of regions
+  // depending on the sizing algorithm.
+  uint max_young_length(uint number_of_heap_regions);
+
+  void heap_size_changed(uint new_number_of_heap_regions);
+  uint min_desired_young_length() {
+    return _min_desired_young_length;
+  }
+  uint max_desired_young_length() {
+    return _max_desired_young_length;
   }
 
-  if (SurvivorRatio < 1) {
-    vm_exit_during_initialization("Invalid survivor ratio specified");
+  bool adaptive_young_list_length() const {
+    return _adaptive_size;
   }
-  CollectorPolicy::initialize_flags();
-  _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags
-}
+};
 
-void G1CollectorPolicy::post_heap_initialize() {
-  uintx max_regions = G1CollectedHeap::heap()->max_regions();
-  size_t max_young_size = (size_t)_young_gen_sizer->max_young_length(max_regions) * HeapRegion::GrainBytes;
-  if (max_young_size != MaxNewSize) {
-    FLAG_SET_ERGO(size_t, MaxNewSize, max_young_size);
-  }
-
-  _ihop_control = create_ihop_control();
-}
-
-G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); }
 
 G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true),
         _min_desired_young_length(0), _max_desired_young_length(0) {
@@ -412,6 +466,29 @@
           &_max_desired_young_length);
 }
 
+void G1CollectorPolicy::post_heap_initialize() {
+  uintx max_regions = G1CollectedHeap::heap()->max_regions();
+  size_t max_young_size = (size_t)_young_gen_sizer->max_young_length(max_regions) * HeapRegion::GrainBytes;
+  if (max_young_size != MaxNewSize) {
+    FLAG_SET_ERGO(size_t, MaxNewSize, max_young_size);
+  }
+
+  _ihop_control = create_ihop_control();
+}
+
+void G1CollectorPolicy::initialize_flags() {
+  if (G1HeapRegionSize != HeapRegion::GrainBytes) {
+    FLAG_SET_ERGO(size_t, G1HeapRegionSize, HeapRegion::GrainBytes);
+  }
+
+  if (SurvivorRatio < 1) {
+    vm_exit_during_initialization("Invalid survivor ratio specified");
+  }
+  CollectorPolicy::initialize_flags();
+  _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags
+}
+
+
 void G1CollectorPolicy::init() {
   // Set aside an initial future to_space.
   _g1 = G1CollectedHeap::heap();
@@ -758,7 +835,7 @@
        curr = curr->get_next_young_region()) {
     SurvRateGroup* group = curr->surv_rate_group();
     if (group == NULL && !curr->is_survivor()) {
-      log_info(gc, verify)("## %s: encountered NULL surv_rate_group", name);
+      log_error(gc, verify)("## %s: encountered NULL surv_rate_group", name);
       ret = false;
     }
 
@@ -766,12 +843,12 @@
       int age = curr->age_in_surv_rate_group();
 
       if (age < 0) {
-        log_info(gc, verify)("## %s: encountered negative age", name);
+        log_error(gc, verify)("## %s: encountered negative age", name);
         ret = false;
       }
 
       if (age <= prev_age) {
-        log_info(gc, verify)("## %s: region ages are not strictly increasing (%d, %d)", name, age, prev_age);
+        log_error(gc, verify)("## %s: region ages are not strictly increasing (%d, %d)", name, age, prev_age);
         ret = false;
       }
       prev_age = age;
@@ -1601,6 +1678,10 @@
   return young_list_length < young_list_max_length;
 }
 
+bool G1CollectorPolicy::adaptive_young_list_length() const {
+  return _young_gen_sizer->adaptive_young_list_length();
+}
+
 void G1CollectorPolicy::update_max_gc_locker_expansion() {
   uint expansion_region_num = 0;
   if (GCLockerEdenExpansionPercent > 0) {
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -43,6 +43,7 @@
 class HeapRegion;
 class CollectionSetChooser;
 class G1IHOPControl;
+class G1YoungGenSizer;
 
 // TraceYoungGenTime collects data on _both_ young and mixed evacuation pauses
 // (the latter may contain non-young regions - i.e. regions that are
@@ -90,81 +91,6 @@
   void print() const;
 };
 
-// There are three command line options related to the young gen size:
-// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is
-// just a short form for NewSize==MaxNewSize). G1 will use its internal
-// heuristics to calculate the actual young gen size, so these options
-// basically only limit the range within which G1 can pick a young gen
-// size. Also, these are general options taking byte sizes. G1 will
-// internally work with a number of regions instead. So, some rounding
-// will occur.
-//
-// If nothing related to the the young gen size is set on the command
-// line we should allow the young gen to be between G1NewSizePercent
-// and G1MaxNewSizePercent of the heap size. This means that every time
-// the heap size changes, the limits for the young gen size will be
-// recalculated.
-//
-// If only -XX:NewSize is set we should use the specified value as the
-// minimum size for young gen. Still using G1MaxNewSizePercent of the
-// heap as maximum.
-//
-// If only -XX:MaxNewSize is set we should use the specified value as the
-// maximum size for young gen. Still using G1NewSizePercent of the heap
-// as minimum.
-//
-// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values.
-// No updates when the heap size changes. There is a special case when
-// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a
-// different heuristic for calculating the collection set when we do mixed
-// collection.
-//
-// If only -XX:NewRatio is set we should use the specified ratio of the heap
-// as both min and max. This will be interpreted as "fixed" just like the
-// NewSize==MaxNewSize case above. But we will update the min and max
-// every time the heap size changes.
-//
-// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is
-// combined with either NewSize or MaxNewSize. (A warning message is printed.)
-class G1YoungGenSizer : public CHeapObj<mtGC> {
-private:
-  enum SizerKind {
-    SizerDefaults,
-    SizerNewSizeOnly,
-    SizerMaxNewSizeOnly,
-    SizerMaxAndNewSize,
-    SizerNewRatio
-  };
-  SizerKind _sizer_kind;
-  uint _min_desired_young_length;
-  uint _max_desired_young_length;
-  bool _adaptive_size;
-  uint calculate_default_min_length(uint new_number_of_heap_regions);
-  uint calculate_default_max_length(uint new_number_of_heap_regions);
-
-  // Update the given values for minimum and maximum young gen length in regions
-  // given the number of heap regions depending on the kind of sizing algorithm.
-  void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length);
-
-public:
-  G1YoungGenSizer();
-  // Calculate the maximum length of the young gen given the number of regions
-  // depending on the sizing algorithm.
-  uint max_young_length(uint number_of_heap_regions);
-
-  void heap_size_changed(uint new_number_of_heap_regions);
-  uint min_desired_young_length() {
-    return _min_desired_young_length;
-  }
-  uint max_desired_young_length() {
-    return _max_desired_young_length;
-  }
-
-  bool adaptive_young_list_length() const {
-    return _adaptive_size;
-  }
-};
-
 class G1CollectorPolicy: public CollectorPolicy {
  private:
   G1IHOPControl* _ihop_control;
@@ -784,9 +710,7 @@
     return _young_list_max_length;
   }
 
-  bool adaptive_young_list_length() const {
-    return _young_gen_sizer->adaptive_young_list_length();
-  }
+  bool adaptive_young_list_length() const;
 
   virtual bool should_process_references() const {
     return true;
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -372,6 +372,16 @@
   return res;
 }
 
+void G1CMRootRegions::notify_scan_done() {
+  MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
+  _scan_in_progress = false;
+  RootRegionScan_lock->notify_all();
+}
+
+void G1CMRootRegions::cancel_scan() {
+  notify_scan_done();
+}
+
 void G1CMRootRegions::scan_finished() {
   assert(scan_in_progress(), "pre-condition");
 
@@ -381,11 +391,7 @@
   }
   _next_survivor = NULL;
 
-  {
-    MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
-    _scan_in_progress = false;
-    RootRegionScan_lock->notify_all();
-  }
+  notify_scan_done();
 }
 
 bool G1CMRootRegions::wait_until_scan_finished() {
@@ -978,13 +984,11 @@
 };
 
 void G1ConcurrentMark::scanRootRegions() {
-  // Start of concurrent marking.
-  ClassLoaderDataGraph::clear_claimed_marks();
-
   // scan_in_progress() will have been set to true only if there was
   // at least one root region to scan. So, if it's false, we
   // should not attempt to do any further work.
   if (root_regions()->scan_in_progress()) {
+    assert(!has_aborted(), "Aborting before root region scanning is finished not supported.");
     GCTraceConcTime(Info, gc) tt("Concurrent Root Region Scan");
 
     _parallel_marking_threads = calc_parallel_marking_threads();
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -229,6 +229,8 @@
   volatile bool        _should_abort;
   HeapRegion* volatile _next_survivor;
 
+  void notify_scan_done();
+
 public:
   G1CMRootRegions();
   // We actually do most of the initialization in this method.
@@ -248,6 +250,8 @@
   // all have been claimed.
   HeapRegion* claim_next();
 
+  void cancel_scan();
+
   // Flag that we're done with root region scanning and notify anyone
   // who's waiting on it. If aborted is false, assume that all regions
   // have been claimed.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapRegionTraceType.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1HEAPREGIONTRACETYPE_HPP
+#define SHARE_VM_GC_G1_G1HEAPREGIONTRACETYPE_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+
+class G1HeapRegionTraceType : AllStatic {
+ public:
+  enum Type {
+    Free,
+    Eden,
+    Survivor,
+    StartsHumongous,
+    ContinuesHumongous,
+    Old,
+    Archive,
+    G1HeapRegionTypeEndSentinel
+  };
+
+  static const char* to_string(G1HeapRegionTraceType::Type type) {
+    switch (type) {
+      case Free:               return "Free";
+      case Eden:               return "Eden";
+      case Survivor:           return "Survivor";
+      case StartsHumongous:    return "Starts Humongous";
+      case ContinuesHumongous: return "Continues Humongous";
+      case Old:                return "Old";
+      case Archive:            return "Archive";
+      default: ShouldNotReachHere(); return NULL;
+    }
+  }
+};
+
+#endif // SHARE_VM_GC_G1_G1HEAPREGIONTRACETYPE_HPP
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -63,10 +63,10 @@
         LogHandle(gc, verify) log;
         log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
         if (_vo == VerifyOption_G1UseMarkWord) {
-          log.info("  Mark word: " PTR_FORMAT, p2i(obj->mark()));
+          log.error("  Mark word: " PTR_FORMAT, p2i(obj->mark()));
         }
         ResourceMark rm;
-        obj->print_on(log.info_stream());
+        obj->print_on(log.error_stream());
         _failures = true;
       }
     }
@@ -111,10 +111,10 @@
       // Verify that the strong code root list for this region
       // contains the nmethod
       if (!hrrs->strong_code_roots_list_contains(_nm)) {
-        log_info(gc, verify)("Code root location " PTR_FORMAT " "
-                             "from nmethod " PTR_FORMAT " not in strong "
-                             "code roots for region [" PTR_FORMAT "," PTR_FORMAT ")",
-                             p2i(p), p2i(_nm), p2i(hr->bottom()), p2i(hr->end()));
+        log_error(gc, verify)("Code root location " PTR_FORMAT " "
+                              "from nmethod " PTR_FORMAT " not in strong "
+                              "code roots for region [" PTR_FORMAT "," PTR_FORMAT ")",
+                              p2i(p), p2i(_nm), p2i(hr->bottom()), p2i(hr->end()));
         _failures = true;
       }
     }
@@ -292,8 +292,8 @@
         r->object_iterate(&not_dead_yet_cl);
         if (_vo != VerifyOption_G1UseNextMarking) {
           if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) {
-            log_info(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT,
-                                 p2i(r->bottom()), p2i(r->end()), r->max_live_bytes(), not_dead_yet_cl.live_bytes());
+            log_error(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT,
+                                  p2i(r->bottom()), p2i(r->end()), r->max_live_bytes(), not_dead_yet_cl.live_bytes());
             _failures = true;
           }
         } else {
@@ -402,13 +402,13 @@
   }
 
   if (failures) {
-    log_info(gc, verify)("Heap after failed verification:");
+    log_error(gc, verify)("Heap after failed verification:");
     // It helps to have the per-region information in the output to
     // help us track down what went wrong. This is why we call
     // print_extended_on() instead of print_on().
     LogHandle(gc, verify) log;
     ResourceMark rm;
-    _g1h->print_extended_on(log.info_stream());
+    _g1h->print_extended_on(log.error_stream());
   }
   guarantee(!failures, "there should not have been any failures");
 }
@@ -597,8 +597,8 @@
             "tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end));
   HeapWord* result = bitmap->getNextMarkedWordAddress(tams, end);
   if (result < end) {
-    log_info(gc, verify)("## wrong marked address on %s bitmap: " PTR_FORMAT, bitmap_name, p2i(result));
-    log_info(gc, verify)("## %s tams: " PTR_FORMAT " end: " PTR_FORMAT, bitmap_name, p2i(tams), p2i(end));
+    log_error(gc, verify)("## wrong marked address on %s bitmap: " PTR_FORMAT, bitmap_name, p2i(result));
+    log_error(gc, verify)("## %s tams: " PTR_FORMAT " end: " PTR_FORMAT, bitmap_name, p2i(tams), p2i(end));
     return false;
   }
   return true;
@@ -623,8 +623,8 @@
     res_n = verify_no_bits_over_tams("next", next_bitmap, ntams, end);
   }
   if (!res_p || !res_n) {
-    log_info(gc, verify)("#### Bitmap verification failed for " HR_FORMAT, HR_FORMAT_PARAMS(hr));
-    log_info(gc, verify)("#### Caller: %s", caller);
+    log_error(gc, verify)("#### Bitmap verification failed for " HR_FORMAT, HR_FORMAT_PARAMS(hr));
+    log_error(gc, verify)("#### Caller: %s", caller);
     return false;
   }
   return true;
@@ -676,41 +676,41 @@
     InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i);
     if (hr->is_humongous()) {
       if (hr->in_collection_set()) {
-        log_info(gc, verify)("## humongous region %u in CSet", i);
+        log_error(gc, verify)("## humongous region %u in CSet", i);
         _failures = true;
         return true;
       }
       if (cset_state.is_in_cset()) {
-        log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
+        log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
         _failures = true;
         return true;
       }
       if (hr->is_continues_humongous() && cset_state.is_humongous()) {
-        log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
+        log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
         _failures = true;
         return true;
       }
     } else {
       if (cset_state.is_humongous()) {
-        log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
+        log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
         _failures = true;
         return true;
       }
       if (hr->in_collection_set() != cset_state.is_in_cset()) {
-        log_info(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
+        log_error(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
                              hr->in_collection_set(), cset_state.value(), i);
         _failures = true;
         return true;
       }
       if (cset_state.is_in_cset()) {
         if (hr->is_young() != (cset_state.is_young())) {
-          log_info(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
+          log_error(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
                                hr->is_young(), cset_state.value(), i);
           _failures = true;
           return true;
         }
         if (hr->is_old() != (cset_state.is_old())) {
-          log_info(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
+          log_error(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
                                hr->is_old(), cset_state.value(), i);
           _failures = true;
           return true;
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -26,11 +26,13 @@
 #include "code/nmethod.hpp"
 #include "gc/g1/g1BlockOffsetTable.inline.hpp"
 #include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1HeapRegionTraceType.hpp"
 #include "gc/g1/g1OopClosures.inline.hpp"
 #include "gc/g1/heapRegion.inline.hpp"
 #include "gc/g1/heapRegionBounds.inline.hpp"
 #include "gc/g1/heapRegionManager.inline.hpp"
 #include "gc/g1/heapRegionRemSet.hpp"
+#include "gc/g1/heapRegionTracer.hpp"
 #include "gc/shared/genOopClosures.inline.hpp"
 #include "gc/shared/liveRange.hpp"
 #include "gc/shared/space.inline.hpp"
@@ -212,10 +214,41 @@
   _gc_efficiency = (double) reclaimable_bytes() / region_elapsed_time_ms;
 }
 
+void HeapRegion::set_free() {
+  report_region_type_change(G1HeapRegionTraceType::Free);
+  _type.set_free();
+}
+
+void HeapRegion::set_eden() {
+  report_region_type_change(G1HeapRegionTraceType::Eden);
+  _type.set_eden();
+}
+
+void HeapRegion::set_eden_pre_gc() {
+  report_region_type_change(G1HeapRegionTraceType::Eden);
+  _type.set_eden_pre_gc();
+}
+
+void HeapRegion::set_survivor() {
+  report_region_type_change(G1HeapRegionTraceType::Survivor);
+  _type.set_survivor();
+}
+
+void HeapRegion::set_old() {
+  report_region_type_change(G1HeapRegionTraceType::Old);
+  _type.set_old();
+}
+
+void HeapRegion::set_archive() {
+  report_region_type_change(G1HeapRegionTraceType::Archive);
+  _type.set_archive();
+}
+
 void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) {
   assert(!is_humongous(), "sanity / pre-condition");
   assert(top() == bottom(), "should be empty");
 
+  report_region_type_change(G1HeapRegionTraceType::StartsHumongous);
   _type.set_starts_humongous();
   _humongous_start_region = this;
 
@@ -227,6 +260,7 @@
   assert(top() == bottom(), "should be empty");
   assert(first_hr->is_starts_humongous(), "pre-condition");
 
+  report_region_type_change(G1HeapRegionTraceType::ContinuesHumongous);
   _type.set_continues_humongous();
   _humongous_start_region = first_hr;
 }
@@ -272,6 +306,15 @@
   record_timestamp();
 }
 
+void HeapRegion::report_region_type_change(G1HeapRegionTraceType::Type to) {
+  HeapRegionTracer::send_region_type_change(_hrm_index,
+                                            get_trace_type(),
+                                            to,
+                                            (uintptr_t)bottom(),
+                                            used(),
+                                            (uint)allocation_context());
+}
+
 CompactibleSpace* HeapRegion::next_compaction_space() const {
   return G1CollectedHeap::heap()->next_compaction_region(this);
 }
@@ -479,7 +522,7 @@
         // Object is in the region. Check that its less than top
         if (_hr->top() <= (HeapWord*)obj) {
           // Object is above top
-          log_info(gc, verify)("Object " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ") is above top " PTR_FORMAT,
+          log_error(gc, verify)("Object " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ") is above top " PTR_FORMAT,
                                p2i(obj), p2i(_hr->bottom()), p2i(_hr->end()), p2i(_hr->top()));
           _failures = true;
           return;
@@ -513,19 +556,19 @@
     if (nm != NULL) {
       // Verify that the nemthod is live
       if (!nm->is_alive()) {
-        log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has dead nmethod " PTR_FORMAT " in its strong code roots",
-                             p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
+        log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has dead nmethod " PTR_FORMAT " in its strong code roots",
+                              p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
         _failures = true;
       } else {
         VerifyStrongCodeRootOopClosure oop_cl(_hr, nm);
         nm->oops_do(&oop_cl);
         if (!oop_cl.has_oops_in_region()) {
-          log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its strong code roots with no pointers into region",
-                               p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
+          log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its strong code roots with no pointers into region",
+                                p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
           _failures = true;
         } else if (oop_cl.failures()) {
-          log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has other failures for nmethod " PTR_FORMAT,
-                               p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
+          log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has other failures for nmethod " PTR_FORMAT,
+                                p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
           _failures = true;
         }
       }
@@ -558,8 +601,8 @@
   // on its strong code root list
   if (is_empty()) {
     if (strong_code_roots_length > 0) {
-      log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] is empty but has " SIZE_FORMAT " code root entries",
-                           p2i(bottom()), p2i(end()), strong_code_roots_length);
+      log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] is empty but has " SIZE_FORMAT " code root entries",
+                            p2i(bottom()), p2i(end()), strong_code_roots_length);
       *failures = true;
     }
     return;
@@ -567,8 +610,8 @@
 
   if (is_continues_humongous()) {
     if (strong_code_roots_length > 0) {
-      log_info(gc, verify)("region " HR_FORMAT " is a continuation of a humongous region but has " SIZE_FORMAT " code root entries",
-                           HR_FORMAT_PARAMS(this), strong_code_roots_length);
+      log_error(gc, verify)("region " HR_FORMAT " is a continuation of a humongous region but has " SIZE_FORMAT " code root entries",
+                            HR_FORMAT_PARAMS(this), strong_code_roots_length);
       *failures = true;
     }
     return;
@@ -661,26 +704,26 @@
           Mutex::_no_safepoint_check_flag);
 
         if (!_failures) {
-          log.info("----------");
+          log.error("----------");
         }
         ResourceMark rm;
         if (!_g1h->is_in_closed_subset(obj)) {
           HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
-          log.info("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
+          log.error("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
             p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end()));
-          print_object(log.info_stream(), _containing_obj);
-          log.info("points to obj " PTR_FORMAT " not in the heap", p2i(obj));
+          print_object(log.error_stream(), _containing_obj);
+          log.error("points to obj " PTR_FORMAT " not in the heap", p2i(obj));
         } else {
           HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
           HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj);
-          log.info("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
+          log.error("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
             p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end()));
-          print_object(log.info_stream(), _containing_obj);
-          log.info("points to dead obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
+          print_object(log.error_stream(), _containing_obj);
+          log.error("points to dead obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
             p2i(obj), p2i(to->bottom()), p2i(to->end()));
-          print_object(log.info_stream(), obj);
+          print_object(log.error_stream(), obj);
         }
-        log.info("----------");
+        log.error("----------");
         _failures = true;
         failed = true;
         _n_failures++;
@@ -730,17 +773,17 @@
             Mutex::_no_safepoint_check_flag);
 
           if (!_failures) {
-            log.info("----------");
+            log.error("----------");
           }
-          log.info("Missing rem set entry:");
-          log.info("Field " PTR_FORMAT " of obj " PTR_FORMAT ", in region " HR_FORMAT,
+          log.error("Missing rem set entry:");
+          log.error("Field " PTR_FORMAT " of obj " PTR_FORMAT ", in region " HR_FORMAT,
             p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from));
           ResourceMark rm;
-          _containing_obj->print_on(log.info_stream());
-          log.info("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to));
-          obj->print_on(log.info_stream());
-          log.info("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field);
-          log.info("----------");
+          _containing_obj->print_on(log.error_stream());
+          log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to));
+          obj->print_on(log.error_stream());
+          log.error("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field);
+          log.error("----------");
           _failures = true;
           if (!failed) _n_failures++;
         }
@@ -774,13 +817,13 @@
                                    (vo == VerifyOption_G1UsePrevMarking &&
                                    ClassLoaderDataGraph::unload_list_contains(klass));
         if (!is_metaspace_object) {
-          log_info(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " "
-                               "not metadata", p2i(klass), p2i(obj));
+          log_error(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " "
+                                "not metadata", p2i(klass), p2i(obj));
           *failures = true;
           return;
         } else if (!klass->is_klass()) {
-          log_info(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " "
-                               "not a klass", p2i(klass), p2i(obj));
+          log_error(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " "
+                                "not a klass", p2i(klass), p2i(obj));
           *failures = true;
           return;
         } else {
@@ -811,7 +854,7 @@
           }
         }
       } else {
-        log_info(gc, verify)(PTR_FORMAT " not an oop", p2i(obj));
+        log_error(gc, verify)(PTR_FORMAT " not an oop", p2i(obj));
         *failures = true;
         return;
       }
@@ -827,13 +870,15 @@
   if (is_region_humongous) {
     oop obj = oop(this->humongous_start_region()->bottom());
     if ((HeapWord*)obj > bottom() || (HeapWord*)obj + obj->size() < bottom()) {
-      log_info(gc, verify)("this humongous region is not part of its' humongous object " PTR_FORMAT, p2i(obj));
+      log_error(gc, verify)("this humongous region is not part of its' humongous object " PTR_FORMAT, p2i(obj));
+      *failures = true;
+      return;
     }
   }
 
   if (!is_region_humongous && p != top()) {
-    log_info(gc, verify)("end of last object " PTR_FORMAT " "
-                         "does not match top " PTR_FORMAT, p2i(p), p2i(top()));
+    log_error(gc, verify)("end of last object " PTR_FORMAT " "
+                          "does not match top " PTR_FORMAT, p2i(p), p2i(top()));
     *failures = true;
     return;
   }
@@ -847,9 +892,9 @@
     HeapWord* addr_1 = p;
     HeapWord* b_start_1 = _bot_part.block_start_const(addr_1);
     if (b_start_1 != p) {
-      log_info(gc, verify)("BOT look up for top: " PTR_FORMAT " "
-                           " yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
-                           p2i(addr_1), p2i(b_start_1), p2i(p));
+      log_error(gc, verify)("BOT look up for top: " PTR_FORMAT " "
+                            " yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
+                            p2i(addr_1), p2i(b_start_1), p2i(p));
       *failures = true;
       return;
     }
@@ -859,9 +904,9 @@
     if (addr_2 < the_end) {
       HeapWord* b_start_2 = _bot_part.block_start_const(addr_2);
       if (b_start_2 != p) {
-        log_info(gc, verify)("BOT look up for top + 1: " PTR_FORMAT " "
-                             " yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
-                             p2i(addr_2), p2i(b_start_2), p2i(p));
+        log_error(gc, verify)("BOT look up for top + 1: " PTR_FORMAT " "
+                              " yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
+                              p2i(addr_2), p2i(b_start_2), p2i(p));
         *failures = true;
         return;
       }
@@ -873,9 +918,9 @@
     if (addr_3 < the_end) {
       HeapWord* b_start_3 = _bot_part.block_start_const(addr_3);
       if (b_start_3 != p) {
-        log_info(gc, verify)("BOT look up for top + diff: " PTR_FORMAT " "
-                             " yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
-                             p2i(addr_3), p2i(b_start_3), p2i(p));
+        log_error(gc, verify)("BOT look up for top + diff: " PTR_FORMAT " "
+                              " yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
+                              p2i(addr_3), p2i(b_start_3), p2i(p));
         *failures = true;
         return;
       }
@@ -885,9 +930,9 @@
     HeapWord* addr_4 = the_end - 1;
     HeapWord* b_start_4 = _bot_part.block_start_const(addr_4);
     if (b_start_4 != p) {
-      log_info(gc, verify)("BOT look up for end - 1: " PTR_FORMAT " "
-                           " yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
-                           p2i(addr_4), p2i(b_start_4), p2i(p));
+      log_error(gc, verify)("BOT look up for end - 1: " PTR_FORMAT " "
+                            " yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
+                            p2i(addr_4), p2i(b_start_4), p2i(p));
       *failures = true;
       return;
     }
@@ -924,7 +969,7 @@
           return;
         }
       } else {
-        log_info(gc, verify)(PTR_FORMAT " not an oop", p2i(obj));
+        log_error(gc, verify)(PTR_FORMAT " not an oop", p2i(obj));
         *failures = true;
         return;
       }
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -27,6 +27,8 @@
 
 #include "gc/g1/g1AllocationContext.hpp"
 #include "gc/g1/g1BlockOffsetTable.hpp"
+#include "gc/g1/g1HeapRegionTraceType.hpp"
+#include "gc/g1/heapRegionTracer.hpp"
 #include "gc/g1/heapRegionType.hpp"
 #include "gc/g1/survRateGroup.hpp"
 #include "gc/shared/ageTable.hpp"
@@ -243,6 +245,8 @@
     return HeapRegion::block_size(addr); // Avoid virtual call
   }
 
+  void report_region_type_change(G1HeapRegionTraceType::Type to);
+
  protected:
   // The index of this region in the heap region sequence.
   uint  _hrm_index;
@@ -427,6 +431,7 @@
 
   const char* get_type_str() const { return _type.get_str(); }
   const char* get_short_type_str() const { return _type.get_short_str(); }
+  G1HeapRegionTraceType::Type get_trace_type() { return _type.get_trace_type(); }
 
   bool is_free() const { return _type.is_free(); }
 
@@ -637,15 +642,15 @@
     }
   }
 
-  void set_free() { _type.set_free(); }
+  void set_free();
 
-  void set_eden()        { _type.set_eden();        }
-  void set_eden_pre_gc() { _type.set_eden_pre_gc(); }
-  void set_survivor()    { _type.set_survivor();    }
+  void set_eden();
+  void set_eden_pre_gc();
+  void set_survivor();
 
-  void set_old() { _type.set_old(); }
+  void set_old();
 
-  void set_archive() { _type.set_archive(); }
+  void set_archive();
 
   // Determine if an object has been allocated since the last
   // mark performed by the collector. This returns true iff the object
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/heapRegionTracer.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/heapRegionTracer.hpp"
+#include "trace/tracing.hpp"
+
+void HeapRegionTracer::send_region_type_change(uint index,
+                                               G1HeapRegionTraceType::Type from,
+                                               G1HeapRegionTraceType::Type to,
+                                               uintptr_t start,
+                                               size_t used,
+                                               uint allocationContext) {
+  EventG1HeapRegionTypeChange e;
+  if (e.should_commit()) {
+    e.set_index(index);
+    e.set_from(from);
+    e.set_to(to);
+    e.set_start(start);
+    e.set_used(used);
+    e.set_allocContext(allocationContext);
+    e.commit();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/heapRegionTracer.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_HEAPREGIONTRACER_HPP
+#define SHARE_VM_GC_G1_HEAPREGIONTRACER_HPP
+
+#include "gc/g1/g1HeapRegionTraceType.hpp"
+#include "memory/allocation.hpp"
+
+class HeapRegionTracer : AllStatic {
+  public:
+    static void send_region_type_change(uint index,
+                                        G1HeapRegionTraceType::Type from,
+                                        G1HeapRegionTraceType::Type to,
+                                        uintptr_t start,
+                                        size_t used,
+                                        uint allocationContext);
+};
+
+#endif // SHARE_VM_GC_G1_HEAPREGIONTRACER_HPP
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "gc/g1/g1HeapRegionTraceType.hpp"
 #include "gc/g1/heapRegionType.hpp"
 
 bool HeapRegionType::is_valid(Tag tag) {
@@ -70,3 +71,19 @@
   // keep some compilers happy
   return NULL;
 }
+
+G1HeapRegionTraceType::Type HeapRegionType::get_trace_type() {
+  hrt_assert_is_valid(_tag);
+  switch (_tag) {
+    case FreeTag:               return G1HeapRegionTraceType::Free;
+    case EdenTag:               return G1HeapRegionTraceType::Eden;
+    case SurvTag:               return G1HeapRegionTraceType::Survivor;
+    case StartsHumongousTag:    return G1HeapRegionTraceType::StartsHumongous;
+    case ContinuesHumongousTag: return G1HeapRegionTraceType::ContinuesHumongous;
+    case OldTag:                return G1HeapRegionTraceType::Old;
+    case ArchiveTag:            return G1HeapRegionTraceType::Archive;
+  }
+  ShouldNotReachHere();
+  // keep some compilers happy
+  return G1HeapRegionTraceType::Free;
+}
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_GC_G1_HEAPREGIONTYPE_HPP
 #define SHARE_VM_GC_G1_HEAPREGIONTYPE_HPP
 
+#include "gc/g1/g1HeapRegionTraceType.hpp"
 #include "memory/allocation.hpp"
 
 #define hrt_assert_is_valid(tag) \
@@ -141,6 +142,7 @@
 
   const char* get_str() const;
   const char* get_short_str() const;
+  G1HeapRegionTraceType::Type get_trace_type();
 
   HeapRegionType() : _tag(FreeTag) { hrt_assert_is_valid(_tag); }
 };
--- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -221,13 +221,13 @@
 
 #ifdef ASSERT
 void SATBMarkQueueSet::dump_active_states(bool expected_active) {
-  log_info(gc, verify)("Expected SATB active state: %s", expected_active ? "ACTIVE" : "INACTIVE");
-  log_info(gc, verify)("Actual SATB active states:");
-  log_info(gc, verify)("  Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
+  log_error(gc, verify)("Expected SATB active state: %s", expected_active ? "ACTIVE" : "INACTIVE");
+  log_error(gc, verify)("Actual SATB active states:");
+  log_error(gc, verify)("  Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
   for (JavaThread* t = Threads::first(); t; t = t->next()) {
-    log_info(gc, verify)("  Thread \"%s\" queue: %s", t->name(), t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
+    log_error(gc, verify)("  Thread \"%s\" queue: %s", t->name(), t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
   }
-  log_info(gc, verify)("  Shared queue: %s", shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
+  log_error(gc, verify)("  Shared queue: %s", shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
 }
 
 void SATBMarkQueueSet::verify_active_states(bool expected_active) {
--- a/hotspot/src/share/vm/gc/g1/youngList.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/youngList.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -99,10 +99,10 @@
   HeapRegion* last = NULL;
   while (curr != NULL) {
     if (!curr->is_young()) {
-      log_info(gc, verify)("### YOUNG REGION " PTR_FORMAT "-" PTR_FORMAT " "
-                           "incorrectly tagged (y: %d, surv: %d)",
-                           p2i(curr->bottom()), p2i(curr->end()),
-                           curr->is_young(), curr->is_survivor());
+      log_error(gc, verify)("### YOUNG REGION " PTR_FORMAT "-" PTR_FORMAT " "
+                            "incorrectly tagged (y: %d, surv: %d)",
+                            p2i(curr->bottom()), p2i(curr->end()),
+                            curr->is_young(), curr->is_survivor());
       ret = false;
     }
     ++length;
@@ -112,8 +112,8 @@
   ret = ret && (length == _length);
 
   if (!ret) {
-    log_info(gc, verify)("### YOUNG LIST seems not well formed!");
-    log_info(gc, verify)("###   list has %u entries, _length is %u", length, _length);
+    log_error(gc, verify)("### YOUNG LIST seems not well formed!");
+    log_error(gc, verify)("###   list has %u entries, _length is %u", length, _length);
   }
 
   return ret;
@@ -123,19 +123,19 @@
   bool ret = true;
 
   if (_length != 0) {
-    log_info(gc, verify)("### YOUNG LIST should have 0 length, not %u", _length);
+    log_error(gc, verify)("### YOUNG LIST should have 0 length, not %u", _length);
     ret = false;
   }
   if (check_sample && _last_sampled_rs_lengths != 0) {
-    log_info(gc, verify)("### YOUNG LIST has non-zero last sampled RS lengths");
+    log_error(gc, verify)("### YOUNG LIST has non-zero last sampled RS lengths");
     ret = false;
   }
   if (_head != NULL) {
-    log_info(gc, verify)("### YOUNG LIST does not have a NULL head");
+    log_error(gc, verify)("### YOUNG LIST does not have a NULL head");
     ret = false;
   }
   if (!ret) {
-    log_info(gc, verify)("### YOUNG LIST does not seem empty");
+    log_error(gc, verify)("### YOUNG LIST does not seem empty");
   }
 
   return ret;
--- a/hotspot/src/share/vm/gc/shared/ageTable.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/ageTable.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "gc/shared/ageTable.inline.hpp"
+#include "gc/shared/ageTableTracer.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "gc/shared/collectorPolicy.hpp"
 #include "gc/shared/gcPolicyCounters.hpp"
@@ -100,17 +101,19 @@
   log_debug(gc, age)("Desired survivor size " SIZE_FORMAT " bytes, new threshold " UINTX_FORMAT " (max threshold " UINTX_FORMAT ")",
                      desired_survivor_size*oopSize, (uintx) result, MaxTenuringThreshold);
 
-  if (log_is_enabled(Trace, gc, age) || UsePerfData) {
+  if (log_is_enabled(Trace, gc, age) || UsePerfData || AgeTableTracer::is_tenuring_distribution_event_enabled()) {
     size_t total = 0;
     uint age = 1;
     while (age < table_size) {
-      total += sizes[age];
-      if (sizes[age] > 0) {
+      size_t wordSize = sizes[age];
+      total += wordSize;
+      if (wordSize > 0) {
         log_trace(gc, age)("- age %3u: " SIZE_FORMAT_W(10) " bytes, " SIZE_FORMAT_W(10) " total",
-                            age, sizes[age]*oopSize, total*oopSize);
+                            age, wordSize*oopSize, total*oopSize);
       }
+      AgeTableTracer::send_tenuring_distribution_event(age, wordSize*oopSize);
       if (UsePerfData) {
-        _perf_sizes[age]->set_value(sizes[age]*oopSize);
+        _perf_sizes[age]->set_value(wordSize*oopSize);
       }
       age++;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/shared/ageTableTracer.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,42 @@
+/*
+ * 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 "precompiled.hpp"
+#include "gc/shared/ageTableTracer.hpp"
+#include "gc/shared/gcId.hpp"
+#include "trace/tracing.hpp"
+
+void AgeTableTracer::send_tenuring_distribution_event(uint age, size_t size) {
+  EventTenuringDistribution e;
+  if (e.should_commit()) {
+    e.set_gcId(GCId::current());
+    e.set_age(age);
+    e.set_size(size);
+    e.commit();
+  }
+}
+
+bool AgeTableTracer::is_tenuring_distribution_event_enabled() {
+  return EventTenuringDistribution::is_enabled();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/shared/ageTableTracer.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_AGETABLETRACER_HPP
+#define SHARE_VM_GC_SHARED_AGETABLETRACER_HPP
+
+#include "memory/allocation.hpp"
+
+class AgeTableTracer : AllStatic {
+  public:
+    static void send_tenuring_distribution_event(uint age, size_t size);
+    static bool is_tenuring_distribution_event_enabled();
+};
+
+#endif // SHARE_VM_GC_SHARED_AGETABLETRACER_HPP
--- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp	Wed Jul 05 21:24:14 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
@@ -60,7 +60,7 @@
 void ConcurrentGCThread::wait_for_universe_init() {
   MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
   while (!is_init_completed() && !_should_terminate) {
-    CGC_lock->wait(Mutex::_no_safepoint_check_flag, 200);
+    CGC_lock->wait(Mutex::_no_safepoint_check_flag, 1);
   }
 }
 
--- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp	Wed Jul 05 21:24:14 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
@@ -32,7 +32,7 @@
   friend class VMStructs;
 
 protected:
-  bool _should_terminate;
+  bool volatile _should_terminate;
   bool _has_terminated;
 
   // Create and start the thread (setting it's priority high.)
--- a/hotspot/src/share/vm/gc/shared/gcHeapSummary.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/gcHeapSummary.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -131,12 +131,14 @@
   size_t  _edenUsed;
   size_t  _edenCapacity;
   size_t  _survivorUsed;
+  uint    _numberOfRegions;
  public:
-   G1HeapSummary(VirtualSpaceSummary& heap_space, size_t heap_used, size_t edenUsed, size_t edenCapacity, size_t survivorUsed) :
-       GCHeapSummary(heap_space, heap_used), _edenUsed(edenUsed), _edenCapacity(edenCapacity), _survivorUsed(survivorUsed) { }
+   G1HeapSummary(VirtualSpaceSummary& heap_space, size_t heap_used, size_t edenUsed, size_t edenCapacity, size_t survivorUsed, uint numberOfRegions) :
+      GCHeapSummary(heap_space, heap_used), _edenUsed(edenUsed), _edenCapacity(edenCapacity), _survivorUsed(survivorUsed), _numberOfRegions(numberOfRegions) { }
    const size_t edenUsed() const { return _edenUsed; }
    const size_t edenCapacity() const { return _edenCapacity; }
    const size_t survivorUsed() const { return _survivorUsed; }
+   const uint   numberOfRegions() const { return _numberOfRegions; }
 
    virtual void accept(GCHeapSummaryVisitor* visitor) const {
      visitor->visit(this);
--- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -359,6 +359,7 @@
       e.set_edenUsedSize(g1_heap_summary->edenUsed());
       e.set_edenTotalSize(g1_heap_summary->edenCapacity());
       e.set_survivorUsedSize(g1_heap_summary->survivorUsed());
+      e.set_numberOfRegions(g1_heap_summary->numberOfRegions());
       e.commit();
     }
   }
--- a/hotspot/src/share/vm/gc/shared/memset_with_concurrent_readers.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/memset_with_concurrent_readers.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -34,7 +34,7 @@
 #if INCLUDE_ALL_GCS
 
 // Unit test
-#ifdef ASSERT
+#ifndef PRODUCT
 
 static unsigned line_byte(const char* line, size_t i) {
   return unsigned(line[i]) & 0xFF;
--- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1091,7 +1091,7 @@
   } else if (reference->is_a(site_DataSectionReference::klass())) {
     int data_offset = site_DataSectionReference::offset(reference);
     if (0 <= data_offset && data_offset < _constants_size) {
-      pd_patch_DataSectionReference(pc_offset, data_offset);
+      pd_patch_DataSectionReference(pc_offset, data_offset, CHECK);
     } else {
       JVMCI_ERROR("data offset 0x%X points outside data section (size 0x%X)", data_offset, _constants_size);
     }
--- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -156,7 +156,7 @@
   jint pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS);
   void pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS);
   void pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS);
-  void pd_patch_DataSectionReference(int pc_offset, int data_offset);
+  void pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS);
   void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS);
   void pd_relocate_JavaMethod(Handle method, jint pc_offset, TRAPS);
   void pd_relocate_poll(address pc, jint mark, TRAPS);
--- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -591,6 +591,13 @@
   // JVMTI -- compiled method notification (must be done outside lock)
   if (nm != NULL) {
     nm->post_compiled_method_load_event();
+
+    if (env == NULL) {
+      // This compile didn't come through the CompileBroker so perform the printing here
+      DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler);
+      nm->maybe_print_nmethod(directive);
+      DirectivesStack::release(directive);
+    }
   }
 
   return result;
--- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -151,6 +151,7 @@
   nonstatic_field(JavaThread,                  _pending_failed_speculation,                   oop)                                   \
   nonstatic_field(JavaThread,                  _pending_transfer_to_interpreter,              bool)                                  \
   nonstatic_field(JavaThread,                  _jvmci_counters,                               jlong*)                                \
+  nonstatic_field(JavaThread,                  _reserved_stack_activation,                    address)                               \
                                                                                                                                      \
   static_field(java_lang_Class,                _klass_offset,                                 int)                                   \
   static_field(java_lang_Class,                _array_klass_offset,                           int)                                   \
@@ -210,6 +211,8 @@
                                                                                                                                      \
   static_field(StubRoutines,                _verify_oop_count,                                jint)                                  \
                                                                                                                                      \
+  static_field(StubRoutines,                _throw_delayed_StackOverflowError_entry,          address)                               \
+                                                                                                                                     \
   static_field(StubRoutines,                _jbyte_arraycopy,                                 address)                               \
   static_field(StubRoutines,                _jshort_arraycopy,                                address)                               \
   static_field(StubRoutines,                _jint_arraycopy,                                  address)                               \
@@ -471,6 +474,7 @@
   declare_constant(Method::_force_inline)                                 \
   declare_constant(Method::_dont_inline)                                  \
   declare_constant(Method::_hidden)                                       \
+  declare_constant(Method::_reserved_stack_access)                        \
                                                                           \
   declare_constant(Method::nonvirtual_vtable_index)                       \
   declare_constant(Method::invalid_vtable_index)                          \
@@ -517,6 +521,7 @@
   declare_function(SharedRuntime::register_finalizer)                     \
   declare_function(SharedRuntime::exception_handler_for_return_address)   \
   declare_function(SharedRuntime::OSR_migration_end)                      \
+  declare_function(SharedRuntime::enable_stack_reserved_zone)             \
   declare_function(SharedRuntime::dsin)                                   \
   declare_function(SharedRuntime::dcos)                                   \
   declare_function(SharedRuntime::dtan)                                   \
--- a/hotspot/src/share/vm/opto/c2_globals.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -182,6 +182,10 @@
           "Unroll loop bodies with node count less than this")              \
           range(0, max_jint / 4)                                            \
                                                                             \
+  product_pd(intx, LoopPercentProfileLimit,                                 \
+             "Unroll loop bodies with % node count of profile limit")       \
+             range(10, 100)                                                 \
+                                                                            \
   product(intx,  LoopMaxUnroll, 16,                                         \
           "Maximum number of unrolls for main loop")                        \
           range(0, max_jint)                                                \
--- a/hotspot/src/share/vm/opto/callGenerator.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/callGenerator.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -825,10 +825,12 @@
         input_not_const = false;
         const TypeOopPtr* oop_ptr = receiver->bottom_type()->is_oopptr();
         ciMethod* target = oop_ptr->const_oop()->as_method_handle()->get_vmtarget();
-        guarantee(!target->is_method_handle_intrinsic(), "should not happen");  // XXX remove
         const int vtable_index = Method::invalid_vtable_index;
-        CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, NULL, true, true);
-        assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
+        CallGenerator* cg = C->call_generator(target, vtable_index,
+                                              false /* call_does_dispatch */,
+                                              jvms,
+                                              true /* allow_inline */,
+                                              PROB_ALWAYS);
         return cg;
       } else {
         const char* msg = "receiver not constant";
@@ -899,13 +901,15 @@
           target = C->optimize_virtual_call(caller, jvms->bci(), klass, klass,
                                             target, receiver_type, is_virtual,
                                             call_does_dispatch, vtable_index, // out-parameters
-                                            /*check_access=*/false);
+                                            false /* check_access */);
           // We lack profiling at this call but type speculation may
           // provide us with a type
           speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL;
         }
-        CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, /*allow_inline=*/true, PROB_ALWAYS, speculative_receiver_type, true, true);
-        assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
+        CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms,
+                                              true /* allow_inline */,
+                                              PROB_ALWAYS,
+                                              speculative_receiver_type);
         return cg;
       } else {
         const char* msg = "member_name not constant";
--- a/hotspot/src/share/vm/opto/castnode.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/castnode.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -37,7 +37,6 @@
 Node* ConstraintCastNode::Identity(PhaseGVN* phase) {
   Node* dom = dominating_cast(phase);
   if (dom != NULL) {
-    assert(_carry_dependency, "only for casts that carry a dependency");
     return dom;
   }
   if (_carry_dependency) {
@@ -110,18 +109,22 @@
 }
 
 TypeNode* ConstraintCastNode::dominating_cast(PhaseTransform *phase) const {
-  if (!carry_dependency()) {
-    return NULL;
-  }
   Node* val = in(1);
   Node* ctl = in(0);
   int opc = Opcode();
   if (ctl == NULL) {
     return NULL;
   }
+  // Range check CastIIs may all end up under a single range check and
+  // in that case only the narrower CastII would be kept by the code
+  // below which would be incorrect.
+  if (is_CastII() && as_CastII()->has_range_check()) {
+    return NULL;
+  }
   for (DUIterator_Fast imax, i = val->fast_outs(imax); i < imax; i++) {
     Node* u = val->fast_out(i);
     if (u != this &&
+        u->outcnt() > 0 &&
         u->Opcode() == opc &&
         u->in(0) != NULL &&
         u->bottom_type()->higher_equal(type())) {
@@ -300,7 +303,6 @@
 Node* CheckCastPPNode::Identity(PhaseGVN* phase) {
   Node* dom = dominating_cast(phase);
   if (dom != NULL) {
-    assert(_carry_dependency, "only for casts that carry a dependency");
     return dom;
   }
   if (_carry_dependency) {
--- a/hotspot/src/share/vm/opto/loopTransform.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -666,7 +666,8 @@
     if (future_unroll_ct > LoopMaxUnroll) return false;
   } else {
     // obey user constraints on vector mapped loops with additional unrolling applied
-    if ((future_unroll_ct / cl->slp_max_unroll()) > LoopMaxUnroll) return false;
+    int unroll_constraint = (cl->slp_max_unroll()) ? cl->slp_max_unroll() : 1;
+    if ((future_unroll_ct / unroll_constraint) > LoopMaxUnroll) return false;
   }
 
   // Check for initial stride being a small enough constant
@@ -689,7 +690,7 @@
   //   Progress defined as current size less than 20% larger than previous size.
   if (UseSuperWord && cl->node_count_before_unroll() > 0 &&
       future_unroll_ct > LoopUnrollMin &&
-      (future_unroll_ct - 1) * 10.0 > cl->profile_trip_cnt() &&
+      (future_unroll_ct - 1) * (100 / LoopPercentProfileLimit) > cl->profile_trip_cnt() &&
       1.2 * cl->node_count_before_unroll() < (double)_body.size()) {
     return false;
   }
@@ -1260,6 +1261,146 @@
   loop->record_for_igvn();
 }
 
+//------------------------------insert_vector_post_loop------------------------
+// Insert a copy of the atomic unrolled vectorized main loop as a post loop,
+// unroll_policy has already informed us that more unrolling is about to happen to
+// the main loop.  The resultant post loop will serve as a vectorized drain loop.
+void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old_new) {
+  if (!loop->_head->is_CountedLoop()) return;
+
+  CountedLoopNode *cl = loop->_head->as_CountedLoop();
+
+  // only process vectorized main loops
+  if (!cl->is_vectorized_loop() || !cl->is_main_loop()) return;
+
+  int slp_max_unroll_factor = cl->slp_max_unroll();
+  int cur_unroll = cl->unrolled_count();
+
+  if (slp_max_unroll_factor == 0) return;
+
+  // only process atomic unroll vector loops (not super unrolled after vectorization)
+  if (cur_unroll != slp_max_unroll_factor) return;
+
+  // we only ever process this one time
+  if (cl->has_atomic_post_loop()) return;
+
+#ifndef PRODUCT
+  if (TraceLoopOpts) {
+    tty->print("PostVector  ");
+    loop->dump_head();
+  }
+#endif
+  C->set_major_progress();
+
+  // Find common pieces of the loop being guarded with pre & post loops
+  CountedLoopNode *main_head = loop->_head->as_CountedLoop();
+  CountedLoopEndNode *main_end = main_head->loopexit();
+  guarantee(main_end != NULL, "no loop exit node");
+  // diagnostic to show loop end is not properly formed
+  assert(main_end->outcnt() == 2, "1 true, 1 false path only");
+  uint dd_main_head = dom_depth(main_head);
+  uint max = main_head->outcnt();
+
+  // mark this loop as processed
+  main_head->mark_has_atomic_post_loop();
+
+  Node *pre_header = main_head->in(LoopNode::EntryControl);
+  Node *init = main_head->init_trip();
+  Node *incr = main_end->incr();
+  Node *limit = main_end->limit();
+  Node *stride = main_end->stride();
+  Node *cmp = main_end->cmp_node();
+  BoolTest::mask b_test = main_end->test_trip();
+
+  //------------------------------
+  // Step A: Create a new post-Loop.
+  Node* main_exit = main_end->proj_out(false);
+  assert(main_exit->Opcode() == Op_IfFalse, "");
+  int dd_main_exit = dom_depth(main_exit);
+
+  // Step A1: Clone the loop body of main.  The clone becomes the vector post-loop.
+  // The main loop pre-header illegally has 2 control users (old & new loops).
+  clone_loop(loop, old_new, dd_main_exit);
+  assert(old_new[main_end->_idx]->Opcode() == Op_CountedLoopEnd, "");
+  CountedLoopNode *post_head = old_new[main_head->_idx]->as_CountedLoop();
+  post_head->set_normal_loop();
+  post_head->set_post_loop(main_head);
+
+  // Reduce the post-loop trip count.
+  CountedLoopEndNode* post_end = old_new[main_end->_idx]->as_CountedLoopEnd();
+  post_end->_prob = PROB_FAIR;
+
+  // Build the main-loop normal exit.
+  IfFalseNode *new_main_exit = new IfFalseNode(main_end);
+  _igvn.register_new_node_with_optimizer(new_main_exit);
+  set_idom(new_main_exit, main_end, dd_main_exit);
+  set_loop(new_main_exit, loop->_parent);
+
+  // Step A2: Build a zero-trip guard for the vector post-loop.  After leaving the
+  // main-loop, the vector post-loop may not execute at all.  We 'opaque' the incr
+  // (the vectorized main-loop trip-counter exit value) because we will be changing
+  // the exit value (via additional unrolling) so we cannot constant-fold away the zero
+  // trip guard until all unrolling is done.
+  Node *zer_opaq = new Opaque1Node(C, incr);
+  Node *zer_cmp = new CmpINode(zer_opaq, limit);
+  Node *zer_bol = new BoolNode(zer_cmp, b_test);
+  register_new_node(zer_opaq, new_main_exit);
+  register_new_node(zer_cmp, new_main_exit);
+  register_new_node(zer_bol, new_main_exit);
+
+  // Build the IfNode
+  IfNode *zer_iff = new IfNode(new_main_exit, zer_bol, PROB_FAIR, COUNT_UNKNOWN);
+  _igvn.register_new_node_with_optimizer(zer_iff);
+  set_idom(zer_iff, new_main_exit, dd_main_exit);
+  set_loop(zer_iff, loop->_parent);
+
+  // Plug in the false-path, taken if we need to skip vector post-loop
+  _igvn.replace_input_of(main_exit, 0, zer_iff);
+  set_idom(main_exit, zer_iff, dd_main_exit);
+  set_idom(main_exit->unique_out(), zer_iff, dd_main_exit);
+  // Make the true-path, must enter the vector post loop
+  Node *zer_taken = new IfTrueNode(zer_iff);
+  _igvn.register_new_node_with_optimizer(zer_taken);
+  set_idom(zer_taken, zer_iff, dd_main_exit);
+  set_loop(zer_taken, loop->_parent);
+  // Plug in the true path
+  _igvn.hash_delete(post_head);
+  post_head->set_req(LoopNode::EntryControl, zer_taken);
+  set_idom(post_head, zer_taken, dd_main_exit);
+
+  Arena *a = Thread::current()->resource_area();
+  VectorSet visited(a);
+  Node_Stack clones(a, main_head->back_control()->outcnt());
+  // Step A3: Make the fall-in values to the vector post-loop come from the
+  // fall-out values of the main-loop.
+  for (DUIterator_Fast imax, i = main_head->fast_outs(imax); i < imax; i++) {
+    Node* main_phi = main_head->fast_out(i);
+    if (main_phi->is_Phi() && main_phi->in(0) == main_head && main_phi->outcnt() >0) {
+      Node *cur_phi = old_new[main_phi->_idx];
+      Node *fallnew = clone_up_backedge_goo(main_head->back_control(),
+                                            post_head->init_control(),
+                                            main_phi->in(LoopNode::LoopBackControl),
+                                            visited, clones);
+      _igvn.hash_delete(cur_phi);
+      cur_phi->set_req(LoopNode::EntryControl, fallnew);
+    }
+  }
+
+  // CastII for the new post loop:
+  bool inserted = cast_incr_before_loop(zer_opaq->in(1), zer_taken, post_head);
+  assert(inserted, "no castII inserted");
+
+  // It's difficult to be precise about the trip-counts
+  // for post loops.  They are usually very short,
+  // so guess that unit vector trips is a reasonable value.
+  post_head->set_profile_trip_cnt((float)slp_max_unroll_factor);
+
+  // Now force out all loop-invariant dominating tests.  The optimizer
+  // finds some, but we _know_ they are all useless.
+  peeled_dom_test_elim(loop, old_new);
+  loop->record_for_igvn();
+}
+
 //------------------------------is_invariant-----------------------------
 // Return true if n is invariant
 bool IdealLoopTree::is_invariant(Node* n) const {
@@ -2608,6 +2749,9 @@
     // and we'd rather unroll the post-RCE'd loop SO... do not unroll if
     // peeling.
     if (should_unroll && !should_peel) {
+      if (SuperWordLoopUnrollAnalysis) {
+        phase->insert_vector_post_loop(this, old_new);
+      }
       phase->do_unroll(this, old_new, true);
     }
 
--- a/hotspot/src/share/vm/opto/loopnode.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/loopnode.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -67,7 +67,9 @@
          HasReductions=128,
          WasSlpAnalyzed=256,
          PassedSlpAnalysis=512,
-         DoUnrollOnly=1024 };
+         DoUnrollOnly=1024,
+         VectorizedLoop=2048,
+         HasAtomicPostLoop=4096 };
   char _unswitch_count;
   enum { _unswitch_max=3 };
 
@@ -86,6 +88,8 @@
   void mark_was_slp() { _loop_flags |= WasSlpAnalyzed; }
   void mark_passed_slp() { _loop_flags |= PassedSlpAnalysis; }
   void mark_do_unroll_only() { _loop_flags |= DoUnrollOnly; }
+  void mark_loop_vectorized() { _loop_flags |= VectorizedLoop; }
+  void mark_has_atomic_post_loop() { _loop_flags |= HasAtomicPostLoop; }
 
   int unswitch_max() { return _unswitch_max; }
   int unswitch_count() { return _unswitch_count; }
@@ -221,6 +225,8 @@
   int has_passed_slp   () const { return (_loop_flags&PassedSlpAnalysis) == PassedSlpAnalysis; }
   int do_unroll_only      () const { return (_loop_flags&DoUnrollOnly) == DoUnrollOnly; }
   int is_main_no_pre_loop() const { return _loop_flags & MainHasNoPreLoop; }
+  int is_vectorized_loop    () const { return (_loop_flags & VectorizedLoop) == VectorizedLoop; }
+  int has_atomic_post_loop  () const { return (_loop_flags & HasAtomicPostLoop) == HasAtomicPostLoop; }
   void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; }
 
   int main_idx() const { return _main_idx; }
@@ -893,6 +899,8 @@
   // Add pre and post loops around the given loop.  These loops are used
   // during RCE, unrolling and aligning loops.
   void insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_new, bool peel_only );
+  // Add a vector post loop between a vector main loop and the current post loop
+  void insert_vector_post_loop(IdealLoopTree *loop, Node_List &old_new);
   // If Node n lives in the back_ctrl block, we clone a private version of n
   // in preheader_ctrl block and return that, otherwise return n.
   Node *clone_up_backedge_goo( Node *back_ctrl, Node *preheader_ctrl, Node *n, VectorSet &visited, Node_Stack &clones );
@@ -1105,6 +1113,8 @@
   Node *place_near_use( Node *useblock ) const;
   Node* try_move_store_before_loop(Node* n, Node *n_ctrl);
   void try_move_store_after_loop(Node* n);
+  bool identical_backtoback_ifs(Node *n);
+  bool can_split_if(Node *n_ctrl);
 
   bool _created_loop_node;
 public:
--- a/hotspot/src/share/vm/opto/loopopts.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/loopopts.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -47,6 +47,14 @@
     return NULL;
   }
 
+  // Splitting range check CastIIs through a loop induction Phi can
+  // cause new Phis to be created that are left unrelated to the loop
+  // induction Phi and prevent optimizations (vectorization)
+  if (n->Opcode() == Op_CastII && n->as_CastII()->has_range_check() &&
+      region->is_CountedLoop() && n->in(1) == region->as_CountedLoop()->phi()) {
+    return NULL;
+  }
+
   int wins = 0;
   assert(!n->is_CFG(), "");
   assert(region->is_Region(), "");
@@ -1020,108 +1028,193 @@
 }
 
 
+bool PhaseIdealLoop::identical_backtoback_ifs(Node *n) {
+  if (!n->is_If()) {
+    return false;
+  }
+  if (!n->in(0)->is_Region()) {
+    return false;
+  }
+  Node* region = n->in(0);
+  Node* dom = idom(region);
+  if (!dom->is_If() || dom->in(1) != n->in(1)) {
+    return false;
+  }
+  IfNode* dom_if = dom->as_If();
+  Node* proj_true = dom_if->proj_out(1);
+  Node* proj_false = dom_if->proj_out(0);
+
+  for (uint i = 1; i < region->req(); i++) {
+    if (is_dominator(proj_true, region->in(i))) {
+      continue;
+    }
+    if (is_dominator(proj_false, region->in(i))) {
+      continue;
+    }
+    return false;
+  }
+
+  return true;
+}
+
+bool PhaseIdealLoop::can_split_if(Node *n_ctrl) {
+  if (C->live_nodes() > 35000) {
+    return false; // Method too big
+  }
+
+  // Do not do 'split-if' if irreducible loops are present.
+  if (_has_irreducible_loops) {
+    return false;
+  }
+
+  if (merge_point_too_heavy(C, n_ctrl)) {
+    return false;
+  }
+
+  // Do not do 'split-if' if some paths are dead.  First do dead code
+  // elimination and then see if its still profitable.
+  for (uint i = 1; i < n_ctrl->req(); i++) {
+    if (n_ctrl->in(i) == C->top()) {
+      return false;
+    }
+  }
+
+  // If trying to do a 'Split-If' at the loop head, it is only
+  // profitable if the cmp folds up on BOTH paths.  Otherwise we
+  // risk peeling a loop forever.
+
+  // CNC - Disabled for now.  Requires careful handling of loop
+  // body selection for the cloned code.  Also, make sure we check
+  // for any input path not being in the same loop as n_ctrl.  For
+  // irreducible loops we cannot check for 'n_ctrl->is_Loop()'
+  // because the alternative loop entry points won't be converted
+  // into LoopNodes.
+  IdealLoopTree *n_loop = get_loop(n_ctrl);
+  for (uint j = 1; j < n_ctrl->req(); j++) {
+    if (get_loop(n_ctrl->in(j)) != n_loop) {
+      return false;
+    }
+  }
+
+  // Check for safety of the merge point.
+  if (!merge_point_safe(n_ctrl)) {
+    return false;
+  }
+
+  return true;
+}
+
 //------------------------------split_if_with_blocks_post----------------------
 // Do the real work in a non-recursive function.  CFG hackery wants to be
 // in the post-order, so it can dirty the I-DOM info and not use the dirtied
 // info.
-void PhaseIdealLoop::split_if_with_blocks_post( Node *n ) {
+void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
 
   // Cloning Cmp through Phi's involves the split-if transform.
   // FastLock is not used by an If
-  if( n->is_Cmp() && !n->is_FastLock() ) {
-    if( C->live_nodes() > 35000 ) return; // Method too big
-
-    // Do not do 'split-if' if irreducible loops are present.
-    if( _has_irreducible_loops )
-      return;
-
+  if (n->is_Cmp() && !n->is_FastLock()) {
     Node *n_ctrl = get_ctrl(n);
     // Determine if the Node has inputs from some local Phi.
     // Returns the block to clone thru.
-    Node *n_blk = has_local_phi_input( n );
-    if( n_blk != n_ctrl ) return;
+    Node *n_blk = has_local_phi_input(n);
+    if (n_blk != n_ctrl) {
+      return;
+    }
 
-    if( merge_point_too_heavy(C, n_ctrl) )
+    if (!can_split_if(n_ctrl)) {
       return;
+    }
 
-    if( n->outcnt() != 1 ) return; // Multiple bool's from 1 compare?
+    if (n->outcnt() != 1) {
+      return; // Multiple bool's from 1 compare?
+    }
     Node *bol = n->unique_out();
-    assert( bol->is_Bool(), "expect a bool here" );
-    if( bol->outcnt() != 1 ) return;// Multiple branches from 1 compare?
+    assert(bol->is_Bool(), "expect a bool here");
+    if (bol->outcnt() != 1) {
+      return;// Multiple branches from 1 compare?
+    }
     Node *iff = bol->unique_out();
 
     // Check some safety conditions
-    if( iff->is_If() ) {        // Classic split-if?
-      if( iff->in(0) != n_ctrl ) return; // Compare must be in same blk as if
+    if (iff->is_If()) {        // Classic split-if?
+      if (iff->in(0) != n_ctrl) {
+        return; // Compare must be in same blk as if
+      }
     } else if (iff->is_CMove()) { // Trying to split-up a CMOVE
       // Can't split CMove with different control edge.
-      if (iff->in(0) != NULL && iff->in(0) != n_ctrl ) return;
-      if( get_ctrl(iff->in(2)) == n_ctrl ||
-          get_ctrl(iff->in(3)) == n_ctrl )
+      if (iff->in(0) != NULL && iff->in(0) != n_ctrl ) {
+        return;
+      }
+      if (get_ctrl(iff->in(2)) == n_ctrl ||
+          get_ctrl(iff->in(3)) == n_ctrl) {
         return;                 // Inputs not yet split-up
-      if ( get_loop(n_ctrl) != get_loop(get_ctrl(iff)) ) {
+      }
+      if (get_loop(n_ctrl) != get_loop(get_ctrl(iff))) {
         return;                 // Loop-invar test gates loop-varying CMOVE
       }
     } else {
       return;  // some other kind of node, such as an Allocate
     }
 
-    // Do not do 'split-if' if some paths are dead.  First do dead code
-    // elimination and then see if its still profitable.
-    for( uint i = 1; i < n_ctrl->req(); i++ )
-      if( n_ctrl->in(i) == C->top() )
-        return;
-
     // When is split-if profitable?  Every 'win' on means some control flow
     // goes dead, so it's almost always a win.
     int policy = 0;
-    // If trying to do a 'Split-If' at the loop head, it is only
-    // profitable if the cmp folds up on BOTH paths.  Otherwise we
-    // risk peeling a loop forever.
-
-    // CNC - Disabled for now.  Requires careful handling of loop
-    // body selection for the cloned code.  Also, make sure we check
-    // for any input path not being in the same loop as n_ctrl.  For
-    // irreducible loops we cannot check for 'n_ctrl->is_Loop()'
-    // because the alternative loop entry points won't be converted
-    // into LoopNodes.
-    IdealLoopTree *n_loop = get_loop(n_ctrl);
-    for( uint j = 1; j < n_ctrl->req(); j++ )
-      if( get_loop(n_ctrl->in(j)) != n_loop )
-        return;
-
-    // Check for safety of the merge point.
-    if( !merge_point_safe(n_ctrl) ) {
+    // Split compare 'n' through the merge point if it is profitable
+    Node *phi = split_thru_phi( n, n_ctrl, policy);
+    if (!phi) {
       return;
     }
 
-    // Split compare 'n' through the merge point if it is profitable
-    Node *phi = split_thru_phi( n, n_ctrl, policy );
-    if( !phi ) return;
-
     // Found a Phi to split thru!
     // Replace 'n' with the new phi
-    _igvn.replace_node( n, phi );
+    _igvn.replace_node(n, phi);
 
     // Now split the bool up thru the phi
-    Node *bolphi = split_thru_phi( bol, n_ctrl, -1 );
+    Node *bolphi = split_thru_phi(bol, n_ctrl, -1);
     guarantee(bolphi != NULL, "null boolean phi node");
 
-    _igvn.replace_node( bol, bolphi );
-    assert( iff->in(1) == bolphi, "" );
+    _igvn.replace_node(bol, bolphi);
+    assert(iff->in(1) == bolphi, "");
 
-    if( bolphi->Value(&_igvn)->singleton() )
+    if (bolphi->Value(&_igvn)->singleton()) {
       return;
+    }
 
     // Conditional-move?  Must split up now
-    if( !iff->is_If() ) {
-      Node *cmovphi = split_thru_phi( iff, n_ctrl, -1 );
-      _igvn.replace_node( iff, cmovphi );
+    if (!iff->is_If()) {
+      Node *cmovphi = split_thru_phi(iff, n_ctrl, -1);
+      _igvn.replace_node(iff, cmovphi);
       return;
     }
 
     // Now split the IF
-    do_split_if( iff );
+    do_split_if(iff);
+    return;
+  }
+
+  // Two identical ifs back to back can be merged
+  if (identical_backtoback_ifs(n) && can_split_if(n->in(0))) {
+    Node *n_ctrl = n->in(0);
+    PhiNode* bolphi = PhiNode::make_blank(n_ctrl, n->in(1));
+    IfNode* dom_if = idom(n_ctrl)->as_If();
+    Node* proj_true = dom_if->proj_out(1);
+    Node* proj_false = dom_if->proj_out(0);
+    Node* con_true = _igvn.makecon(TypeInt::ONE);
+    Node* con_false = _igvn.makecon(TypeInt::ZERO);
+
+    for (uint i = 1; i < n_ctrl->req(); i++) {
+      if (is_dominator(proj_true, n_ctrl->in(i))) {
+        bolphi->init_req(i, con_true);
+      } else {
+        assert(is_dominator(proj_false, n_ctrl->in(i)), "bad if");
+        bolphi->init_req(i, con_false);
+      }
+    }
+    register_new_node(bolphi, n_ctrl);
+    _igvn.replace_input_of(n, 1, bolphi);
+
+    // Now split the IF
+    do_split_if(n);
     return;
   }
 
--- a/hotspot/src/share/vm/opto/memnode.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1709,38 +1709,10 @@
             // unsafe field access may not have a constant offset
             C->has_unsafe_access(),
             "Field accesses must be precise" );
-    // For oop loads, we expect the _type to be precise
-    if (klass == env->String_klass() &&
-        adr->is_AddP() && off != Type::OffsetBot) {
-      // For constant Strings treat the final fields as compile time constants.
-      // While we can list what field types java.lang.String has, it is more
-      // future-proof to handle all possible field types, anticipating future
-      // changes and experiments in String code.
-      Node* base = adr->in(AddPNode::Base);
-      const TypeOopPtr* t = phase->type(base)->isa_oopptr();
-      if (t != NULL && t->singleton()) {
-        ciField* field = env->String_klass()->get_field_by_offset(off, false);
-        if (field != NULL && field->is_final()) {
-          ciObject* string = t->const_oop();
-          ciConstant constant = string->as_instance()->field_value(field);
-          // Type::make_from_constant does not handle narrow oops, so handle it here.
-          // Everything else can use the factory method.
-          if ((constant.basic_type() == T_ARRAY || constant.basic_type() == T_OBJECT)
-                  && adr->bottom_type()->is_ptr_to_narrowoop()) {
-            return TypeNarrowOop::make_from_constant(constant.as_object(), true);
-          } else {
-            return Type::make_from_constant(constant, true);
-          }
-        }
-      }
-    }
+    // For oop loads, we expect the _type to be precise.
     // Optimizations for constant objects
     ciObject* const_oop = tinst->const_oop();
     if (const_oop != NULL) {
-      // For constant Boxed value treat the target field as a compile time constant.
-      if (tinst->is_ptr_to_boxed_value()) {
-        return tinst->get_const_boxed_value();
-      } else
       // For constant CallSites treat the target field as a compile time constant.
       if (const_oop->is_call_site()) {
         ciCallSite* call_site = const_oop->as_call_site();
--- a/hotspot/src/share/vm/opto/stringopts.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/stringopts.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1552,8 +1552,7 @@
 
   if (str->is_Con()) {
     // Constant source string
-    const TypeOopPtr* t = kit.gvn().type(src_array)->isa_oopptr();
-    ciTypeArray* src_array_type = t->const_oop()->as_type_array();
+    ciTypeArray* src_array_type = get_constant_value(kit, str);
 
     // Check encoding of constant string
     bool src_is_byte = (get_constant_coder(kit, str) == java_lang_String::CODER_LATIN1);
@@ -1673,9 +1672,15 @@
 
 int PhaseStringOpts::get_constant_length(GraphKit& kit, Node* str) {
   assert(str->is_Con(), "String must be constant");
-  Node* src_array = kit.load_String_value(kit.control(), str);
-  const TypeOopPtr* t = kit.gvn().type(src_array)->isa_oopptr();
-  return t->const_oop()->as_type_array()->length();
+  return get_constant_value(kit, str)->length();
+}
+
+ciTypeArray* PhaseStringOpts::get_constant_value(GraphKit& kit, Node* str) {
+  assert(str->is_Con(), "String must be constant");
+  const TypeOopPtr* str_type = kit.gvn().type(str)->isa_oopptr();
+  ciInstance* str_instance = str_type->const_oop()->as_instance();
+  ciObject* src_array = str_instance->field_value_by_offset(java_lang_String::value_offset_in_bytes()).as_object();
+  return src_array->as_type_array();
 }
 
 void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
--- a/hotspot/src/share/vm/opto/stringopts.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/stringopts.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -97,6 +97,9 @@
   // Returns the length of a constant string
   int get_constant_length(GraphKit& kit, Node* str);
 
+  // Returns the value array of a constant string
+  ciTypeArray* get_constant_value(GraphKit& kit, Node* str);
+
   // Clean up any leftover nodes
   void record_dead_node(Node* node);
   void remove_dead_nodes();
--- a/hotspot/src/share/vm/opto/superword.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/opto/superword.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -2253,6 +2253,9 @@
           C->set_major_progress();
         }
         cl->mark_do_unroll_only();
+        if (do_reserve_copy()) {
+          cl->mark_loop_vectorized();
+        }
       }
     }
   }
--- a/hotspot/src/share/vm/prims/methodComparator.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/prims/methodComparator.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -34,9 +34,6 @@
 BytecodeStream *MethodComparator::_s_new;
 ConstantPool* MethodComparator::_old_cp;
 ConstantPool* MethodComparator::_new_cp;
-BciMap *MethodComparator::_bci_map;
-bool MethodComparator::_switchable_test;
-GrowableArray<int> *MethodComparator::_fwd_jmps;
 
 bool MethodComparator::methods_EMCP(Method* old_method, Method* new_method) {
   if (old_method->code_size() != new_method->code_size())
@@ -55,7 +52,6 @@
   BytecodeStream s_new(new_method);
   _s_old = &s_old;
   _s_new = &s_new;
-  _switchable_test = false;
   Bytecodes::Code c_old, c_new;
 
   while ((c_old = s_old.next()) >= 0) {
@@ -68,64 +64,6 @@
   return true;
 }
 
-
-bool MethodComparator::methods_switchable(Method* old_method, Method* new_method,
-                                          BciMap &bci_map) {
-  if (old_method->code_size() > new_method->code_size())
-    // Something has definitely been deleted in the new method, compared to the old one.
-    return false;
-
-  if (! check_stack_and_locals_size(old_method, new_method))
-    return false;
-
-  _old_cp = old_method->constants();
-  _new_cp = new_method->constants();
-  BytecodeStream s_old(old_method);
-  BytecodeStream s_new(new_method);
-  _s_old = &s_old;
-  _s_new = &s_new;
-  _bci_map = &bci_map;
-  _switchable_test = true;
-  GrowableArray<int> fwd_jmps(16);
-  _fwd_jmps = &fwd_jmps;
-  Bytecodes::Code c_old, c_new;
-
-  while ((c_old = s_old.next()) >= 0) {
-    if ((c_new = s_new.next()) < 0)
-      return false;
-    if (! (c_old == c_new && args_same(c_old, c_new))) {
-      int old_bci = s_old.bci();
-      int new_st_bci = s_new.bci();
-      bool found_match = false;
-      do {
-        c_new = s_new.next();
-        if (c_new == c_old && args_same(c_old, c_new)) {
-          found_match = true;
-          break;
-        }
-      } while (c_new >= 0);
-      if (! found_match)
-        return false;
-      int new_end_bci = s_new.bci();
-      bci_map.store_fragment_location(old_bci, new_st_bci, new_end_bci);
-    }
-  }
-
-  // Now we can test all forward jumps
-  for (int i = 0; i < fwd_jmps.length() / 2; i++) {
-    if (! bci_map.old_and_new_locations_same(fwd_jmps.at(i*2), fwd_jmps.at(i*2+1))) {
-      RC_TRACE(0x00800000,
-        ("Fwd jump miss: old dest = %d, calc new dest = %d, act new dest = %d",
-        fwd_jmps.at(i*2), bci_map.new_bci_for_old(fwd_jmps.at(i*2)),
-        fwd_jmps.at(i*2+1)));
-      return false;
-    }
-  }
-
-  return true;
-}
-
-
 bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) {
   // BytecodeStream returns the correct standard Java bytecodes for various "fast"
   // bytecode versions, so we don't have to bother about them here..
@@ -275,22 +213,8 @@
   case Bytecodes::_jsr       : {
     int old_ofs = _s_old->bytecode().get_offset_s2(c_old);
     int new_ofs = _s_new->bytecode().get_offset_s2(c_new);
-    if (_switchable_test) {
-      int old_dest = _s_old->bci() + old_ofs;
-      int new_dest = _s_new->bci() + new_ofs;
-      if (old_ofs < 0 && new_ofs < 0) {
-        if (! _bci_map->old_and_new_locations_same(old_dest, new_dest))
-          return false;
-      } else if (old_ofs > 0 && new_ofs > 0) {
-        _fwd_jmps->append(old_dest);
-        _fwd_jmps->append(new_dest);
-      } else {
-        return false;
-      }
-    } else {
-      if (old_ofs != new_ofs)
-        return false;
-    }
+    if (old_ofs != new_ofs)
+      return false;
     break;
   }
 
@@ -312,73 +236,19 @@
   case Bytecodes::_jsr_w  : {
     int old_ofs = _s_old->bytecode().get_offset_s4(c_old);
     int new_ofs = _s_new->bytecode().get_offset_s4(c_new);
-    if (_switchable_test) {
-      int old_dest = _s_old->bci() + old_ofs;
-      int new_dest = _s_new->bci() + new_ofs;
-      if (old_ofs < 0 && new_ofs < 0) {
-        if (! _bci_map->old_and_new_locations_same(old_dest, new_dest))
-          return false;
-      } else if (old_ofs > 0 && new_ofs > 0) {
-        _fwd_jmps->append(old_dest);
-        _fwd_jmps->append(new_dest);
-      } else {
-        return false;
-      }
-    } else {
-      if (old_ofs != new_ofs)
-        return false;
-    }
+    if (old_ofs != new_ofs)
+      return false;
     break;
   }
 
   case Bytecodes::_lookupswitch : // fall through
   case Bytecodes::_tableswitch  : {
-    if (_switchable_test) {
-      address aligned_bcp_old = (address) round_to((intptr_t)_s_old->bcp() + 1, jintSize);
-      address aligned_bcp_new = (address) round_to((intptr_t)_s_new->bcp() + 1, jintSize);
-      int default_old = (int) Bytes::get_Java_u4(aligned_bcp_old);
-      int default_new = (int) Bytes::get_Java_u4(aligned_bcp_new);
-      _fwd_jmps->append(_s_old->bci() + default_old);
-      _fwd_jmps->append(_s_new->bci() + default_new);
-      if (c_old == Bytecodes::_lookupswitch) {
-        int npairs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + jintSize);
-        int npairs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + jintSize);
-        if (npairs_old != npairs_new)
-          return false;
-        for (int i = 0; i < npairs_old; i++) {
-          int match_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (2+2*i)*jintSize);
-          int match_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (2+2*i)*jintSize);
-          if (match_old != match_new)
-            return false;
-          int ofs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (2+2*i+1)*jintSize);
-          int ofs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (2+2*i+1)*jintSize);
-          _fwd_jmps->append(_s_old->bci() + ofs_old);
-          _fwd_jmps->append(_s_new->bci() + ofs_new);
-        }
-      } else if (c_old == Bytecodes::_tableswitch) {
-        int lo_old = (int) Bytes::get_Java_u4(aligned_bcp_old + jintSize);
-        int lo_new = (int) Bytes::get_Java_u4(aligned_bcp_new + jintSize);
-        if (lo_old != lo_new)
-          return false;
-        int hi_old = (int) Bytes::get_Java_u4(aligned_bcp_old + 2*jintSize);
-        int hi_new = (int) Bytes::get_Java_u4(aligned_bcp_new + 2*jintSize);
-        if (hi_old != hi_new)
-          return false;
-        for (int i = 0; i < hi_old - lo_old + 1; i++) {
-          int ofs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (3+i)*jintSize);
-          int ofs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (3+i)*jintSize);
-          _fwd_jmps->append(_s_old->bci() + ofs_old);
-          _fwd_jmps->append(_s_new->bci() + ofs_new);
-        }
-      }
-    } else { // !_switchable_test, can use fast rough compare
-      int len_old = _s_old->instruction_size();
-      int len_new = _s_new->instruction_size();
-      if (len_old != len_new)
-        return false;
-      if (memcmp(_s_old->bcp(), _s_new->bcp(), len_old) != 0)
-        return false;
-    }
+    int len_old = _s_old->instruction_size();
+    int len_new = _s_new->instruction_size();
+    if (len_old != len_new)
+      return false;
+    if (memcmp(_s_old->bcp(), _s_new->bcp(), len_old) != 0)
+      return false;
     break;
   }
   }
--- a/hotspot/src/share/vm/prims/methodComparator.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/prims/methodComparator.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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,8 +29,6 @@
 #include "oops/constantPool.hpp"
 #include "oops/method.hpp"
 
-class BciMap;
-
 // methodComparator provides an interface for determining if methods of
 // different versions of classes are equivalent or switchable
 
@@ -39,9 +37,6 @@
   static BytecodeStream *_s_old, *_s_new;
   static ConstantPool* _old_cp;
   static ConstantPool* _new_cp;
-  static BciMap *_bci_map;
-  static bool _switchable_test;
-  static GrowableArray<int> *_fwd_jmps;
 
   static bool args_same(Bytecodes::Code c_old, Bytecodes::Code c_new);
   static bool pool_constants_same(int cpi_old, int cpi_new);
@@ -55,79 +50,6 @@
   // these indices eventually point to the same constants for both method versions.
   static bool methods_EMCP(Method* old_method, Method* new_method);
 
-  static bool methods_switchable(Method* old_method, Method* new_method, BciMap &bci_map);
-};
-
-
-// ByteCode Index Map. For two versions of the same method, where the new version may contain
-// fragments not found in the old version, provides a mapping from an index of a bytecode in
-// the old method to the index of the same bytecode in the new method.
-
-class BciMap {
- private:
-  int *_old_bci, *_new_st_bci, *_new_end_bci;
-  int _cur_size, _cur_pos;
-  int _pos;
-
- public:
-  BciMap() {
-    _cur_size = 50;
-    _old_bci = (int*) malloc(sizeof(int) * _cur_size);
-    _new_st_bci = (int*) malloc(sizeof(int) * _cur_size);
-    _new_end_bci = (int*) malloc(sizeof(int) * _cur_size);
-    _cur_pos = 0;
-  }
-
-  ~BciMap() {
-    free(_old_bci);
-    free(_new_st_bci);
-    free(_new_end_bci);
-  }
-
-  // Store the position of an added fragment, e.g.
-  //
-  //                              |<- old_bci
-  // -----------------------------------------
-  // Old method   |invokevirtual 5|aload 1|...
-  // -----------------------------------------
-  //
-  //                                 |<- new_st_bci          |<- new_end_bci
-  // --------------------------------------------------------------------
-  // New method       |invokevirual 5|aload 2|invokevirtual 6|aload 1|...
-  // --------------------------------------------------------------------
-  //                                 ^^^^^^^^^^^^^^^^^^^^^^^^
-  //                                    Added fragment
-
-  void store_fragment_location(int old_bci, int new_st_bci, int new_end_bci) {
-    if (_cur_pos == _cur_size) {
-      _cur_size += 10;
-      _old_bci = (int*) realloc(_old_bci, sizeof(int) * _cur_size);
-      _new_st_bci = (int*) realloc(_new_st_bci, sizeof(int) * _cur_size);
-      _new_end_bci = (int*) realloc(_new_end_bci, sizeof(int) * _cur_size);
-    }
-    _old_bci[_cur_pos] = old_bci;
-    _new_st_bci[_cur_pos] = new_st_bci;
-    _new_end_bci[_cur_pos] = new_end_bci;
-    _cur_pos++;
-  }
-
-  int new_bci_for_old(int old_bci) {
-    if (_cur_pos == 0 || old_bci < _old_bci[0]) return old_bci;
-    _pos = 1;
-    while (_pos < _cur_pos && old_bci >= _old_bci[_pos])
-      _pos++;
-    return _new_end_bci[_pos-1] + (old_bci - _old_bci[_pos-1]);
-  }
-
-  // Test if two indexes - one in the old method and another in the new one - correspond
-  // to the same bytecode
-  bool old_and_new_locations_same(int old_dest_bci, int new_dest_bci) {
-    if (new_bci_for_old(old_dest_bci) == new_dest_bci)
-      return true;
-    else if (_old_bci[_pos-1] == old_dest_bci)
-      return (new_dest_bci == _new_st_bci[_pos-1]);
-    else return false;
-  }
 };
 
 #endif // SHARE_VM_PRIMS_METHODCOMPARATOR_HPP
--- a/hotspot/src/share/vm/prims/methodHandles.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -63,30 +63,21 @@
 bool MethodHandles::_enabled = false; // set true after successful native linkage
 MethodHandlesAdapterBlob* MethodHandles::_adapter_code = NULL;
 
-
 /**
  * Generates method handle adapters. Returns 'false' if memory allocation
  * failed and true otherwise.
  */
-bool MethodHandles::generate_adapters() {
-  if (SystemDictionary::MethodHandle_klass() == NULL) {
-    return true;
-  }
-
+void MethodHandles::generate_adapters() {
+  assert(SystemDictionary::MethodHandle_klass() != NULL, "should be present");
   assert(_adapter_code == NULL, "generate only once");
 
   ResourceMark rm;
   TraceTime timer("MethodHandles adapters generation", TraceStartupTime);
   _adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size);
-  if (_adapter_code == NULL) {
-     return false;
-  }
-
   CodeBuffer code(_adapter_code);
   MethodHandlesAdapterGenerator g(&code);
   g.generate();
   code.log_section_sizes("MethodHandlesAdapterBlob");
-  return true;
 }
 
 //------------------------------------------------------------------------------
@@ -1436,53 +1427,31 @@
 };
 
 /**
- * Helper method to register native methods.
- */
-static bool register_natives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) {
-  int status = env->RegisterNatives(clazz, methods, nMethods);
-  if (status != JNI_OK || env->ExceptionOccurred()) {
-    warning("JSR 292 method handle code is mismatched to this JVM.  Disabling support.");
-    env->ExceptionClear();
-    return false;
-  }
-  return true;
-}
-
-/**
  * This one function is exported, used by NativeLookup.
  */
 JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) {
   assert(!MethodHandles::enabled(), "must not be enabled");
-  bool enable_MH = true;
+  assert(SystemDictionary::MethodHandle_klass() != NULL, "should be present");
 
-  jclass MH_class = NULL;
-  if (SystemDictionary::MethodHandle_klass() == NULL) {
-    enable_MH = false;
-  } else {
-    oop mirror = SystemDictionary::MethodHandle_klass()->java_mirror();
-    MH_class = (jclass) JNIHandles::make_local(env, mirror);
-  }
+  oop mirror = SystemDictionary::MethodHandle_klass()->java_mirror();
+  jclass MH_class = (jclass) JNIHandles::make_local(env, mirror);
 
-  if (enable_MH) {
+  {
     ThreadToNativeFromVM ttnfv(thread);
 
-    if (enable_MH) {
-      enable_MH = register_natives(env, MHN_class, MHN_methods, sizeof(MHN_methods)/sizeof(JNINativeMethod));
-    }
-    if (enable_MH) {
-      enable_MH = register_natives(env, MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod));
-    }
+    int status = env->RegisterNatives(MHN_class, MHN_methods, sizeof(MHN_methods)/sizeof(JNINativeMethod));
+    guarantee(status == JNI_OK && !env->ExceptionOccurred(),
+              "register java.lang.invoke.MethodHandleNative natives");
+
+    status = env->RegisterNatives(MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod));
+    guarantee(status == JNI_OK && !env->ExceptionOccurred(),
+              "register java.lang.invoke.MethodHandle natives");
   }
 
   if (TraceInvokeDynamic) {
     tty->print_cr("MethodHandle support loaded (using LambdaForms)");
   }
 
-  if (enable_MH) {
-    if (MethodHandles::generate_adapters() == false) {
-      THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), "Out of space in CodeCache for method handle adapters");
-    }
-    MethodHandles::set_enabled(true);
-  }
+  MethodHandles::set_enabled(true);
 }
 JVM_END
--- a/hotspot/src/share/vm/prims/methodHandles.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/prims/methodHandles.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -81,7 +81,7 @@
   static void flush_dependent_nmethods(Handle call_site, Handle target);
 
   // Generate MethodHandles adapters.
-  static bool generate_adapters();
+  static void generate_adapters();
 
   // Called from MethodHandlesAdapterGenerator.
   static address generate_method_handle_interpreter_entry(MacroAssembler* _masm, vmIntrinsics::ID iid);
--- a/hotspot/src/share/vm/prims/unsafe.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/prims/unsafe.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -660,6 +660,36 @@
   Copy::conjoint_memory_atomic(src, dst, sz);
 UNSAFE_END
 
+// This function is a leaf since if the source and destination are both in native memory
+// the copy may potentially be very large, and we don't want to disable GC if we can avoid it.
+// If either source or destination (or both) are on the heap, the function will enter VM using
+// JVM_ENTRY_FROM_LEAF
+JVM_LEAF(void, Unsafe_CopySwapMemory0(JNIEnv *env, jobject unsafe, jobject srcObj, jlong srcOffset, jobject dstObj, jlong dstOffset, jlong size, jlong elemSize)) {
+  UnsafeWrapper("Unsafe_CopySwapMemory0");
+
+  size_t sz = (size_t)size;
+  size_t esz = (size_t)elemSize;
+
+  if (srcObj == NULL && dstObj == NULL) {
+    // Both src & dst are in native memory
+    address src = (address)srcOffset;
+    address dst = (address)dstOffset;
+
+    Copy::conjoint_swap(src, dst, sz, esz);
+  } else {
+    // At least one of src/dst are on heap, transition to VM to access raw pointers
+
+    JVM_ENTRY_FROM_LEAF(env, void, Unsafe_CopySwapMemory0) {
+      oop srcp = JNIHandles::resolve(srcObj);
+      oop dstp = JNIHandles::resolve(dstObj);
+
+      address src = (address)index_oop_from_field_offset_long(srcp, srcOffset);
+      address dst = (address)index_oop_from_field_offset_long(dstp, dstOffset);
+
+      Copy::conjoint_swap(src, dst, sz, esz);
+    } JVM_END
+  }
+} JVM_END
 
 ////// Random queries
 
@@ -1363,6 +1393,7 @@
     {CC "getLoadAverage",     CC "([DI)I",               FN_PTR(Unsafe_Loadavg)},
 
     {CC "copyMemory",         CC "(" OBJ "J" OBJ "JJ)V", FN_PTR(Unsafe_CopyMemory)},
+    {CC "copySwapMemory0",    CC "(" OBJ "J" OBJ "JJJ)V", FN_PTR(Unsafe_CopySwapMemory0)},
     {CC "setMemory",          CC "(" OBJ "JJB)V",        FN_PTR(Unsafe_SetMemory)},
 
     {CC "defineAnonymousClass", CC "(" DAC_Args ")" CLS, FN_PTR(Unsafe_DefineAnonymousClass)},
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -333,6 +333,8 @@
   // --- Non-alias flags - sorted by obsolete_in then expired_in:
   { "MaxGCMinorPauseMillis",        JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
   { "UseParNewGC",                  JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
+  { "ConvertSleepToYield",          JDK_Version::jdk(9), JDK_Version::jdk(10),     JDK_Version::jdk(11) },
+  { "ConvertYieldToSleep",          JDK_Version::jdk(9), JDK_Version::jdk(10),     JDK_Version::jdk(11) },
 
   // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in:
   { "DefaultMaxRAMFraction",        JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
--- a/hotspot/src/share/vm/runtime/globals.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1239,9 +1239,8 @@
   product_pd(bool, DontYieldALot,                                           \
           "Throw away obvious excess yield calls")                          \
                                                                             \
-  product_pd(bool, ConvertSleepToYield,                                     \
-          "Convert sleep(0) to thread yield "                               \
-          "(may be off for Solaris to improve GUI)")                        \
+  product(bool, ConvertSleepToYield, true,                                  \
+          "Convert sleep(0) to thread yield ")                              \
                                                                             \
   product(bool, ConvertYieldToSleep, false,                                 \
           "Convert yield to a sleep of MinSleepInterval to simulate Win32 " \
@@ -1279,10 +1278,6 @@
   experimental(intx, hashCode, 5,                                           \
                "(Unstable) select hashCode generation algorithm")           \
                                                                             \
-  experimental(intx, WorkAroundNPTLTimedWaitHang, 0,                        \
-               "(Unstable, Linux-specific) "                                \
-               "avoid NPTL-FUTEX hang pthread_cond_timedwait")              \
-                                                                            \
   product(bool, FilterSpuriousWakeups, true,                                \
           "When true prevents OS-level spurious, or premature, wakeups "    \
           "from Object.wait (Ignored for Windows)")                         \
@@ -2012,11 +2007,15 @@
           range(min_intx, 100)                                              \
                                                                             \
   product(uintx, InitiatingHeapOccupancyPercent, 45,                        \
-          "Percentage of the (entire) heap occupancy to start a "           \
-          "concurrent GC cycle. It is used by GCs that trigger a "          \
-          "concurrent GC cycle based on the occupancy of the entire heap, " \
-          "not just one of the generations (e.g., G1). A value of 0 "       \
-          "denotes 'do constant GC cycles'.")                               \
+          "The percent occupancy (IHOP) of the current old generation "     \
+          "capacity above which a concurrent mark cycle will be initiated " \
+          "Its value may change over time if adaptive IHOP is enabled, "    \
+          "otherwise the value remains constant. "                          \
+          "In the latter case a value of 0 will result as frequent as "     \
+          "possible concurrent marking cycles. A value of 100 disables "    \
+          "concurrent marking. "                                            \
+          "Fragmentation waste in the old generation is not considered "    \
+          "free space in this calculation. (G1 collector only)")            \
           range(0, 100)                                                     \
                                                                             \
   manageable(intx, CMSTriggerInterval, -1,                                  \
--- a/hotspot/src/share/vm/runtime/init.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/runtime/init.cpp	Wed Jul 05 21:24:14 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
@@ -145,6 +145,7 @@
   }
   javaClasses_init();   // must happen after vtable initialization
   stubRoutines_init2(); // note: StubRoutines need 2-phase init
+  MethodHandles::generate_adapters();
   CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::StubRoutines2);
 
 #if INCLUDE_NMT
@@ -181,8 +182,7 @@
   }
 }
 
-
-static bool _init_completed = false;
+static volatile bool _init_completed = false;
 
 bool is_init_completed() {
   return _init_completed;
--- a/hotspot/src/share/vm/runtime/interfaceSupport.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/runtime/interfaceSupport.hpp	Wed Jul 05 21:24:14 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
@@ -417,6 +417,14 @@
   os::verify_stack_alignment();                                      \
   /* begin of body */
 
+#define VM_ENTRY_BASE_FROM_LEAF(result_type, header, thread)         \
+  TRACE_CALL(result_type, header)                                    \
+  debug_only(ResetNoHandleMark __rnhm;)                              \
+  HandleMarkCleaner __hm(thread);                                    \
+  Thread* THREAD = thread;                                           \
+  os::verify_stack_alignment();                                      \
+  /* begin of body */
+
 
 // ENTRY routines may lock, GC and throw exceptions
 
@@ -584,6 +592,14 @@
     VM_LEAF_BASE(result_type, header)
 
 
+#define JVM_ENTRY_FROM_LEAF(env, result_type, header)                \
+  { {                                                                \
+    JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
+    ThreadInVMfromNative __tiv(thread);                              \
+    debug_only(VMNativeEntryWrapper __vew;)                          \
+    VM_ENTRY_BASE_FROM_LEAF(result_type, header, thread)
+
+
 #define JVM_END } }
 
 #endif // SHARE_VM_RUNTIME_INTERFACESUPPORT_HPP
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -359,6 +359,11 @@
   static address clean_opt_virtual_call_entry();
   static address clean_static_call_entry();
 
+#if defined(X86) && defined(COMPILER1)
+  // For Object.hashCode, System.identityHashCode try to pull hashCode from object header if available.
+  static void inline_check_hashcode_from_object_header(MacroAssembler* masm, methodHandle method, Register obj_reg, Register result);
+#endif // X86 && COMPILER1
+
  public:
 
   // Read the array of BasicTypes from a Java signature, and compute where
--- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -37,7 +37,7 @@
 
 StubCodeDesc* StubCodeDesc::_list = NULL;
 int           StubCodeDesc::_count = 0;
-
+bool          StubCodeDesc::_frozen = false;
 
 StubCodeDesc* StubCodeDesc::desc_for(address pc) {
   StubCodeDesc* p = _list;
@@ -46,20 +46,23 @@
   return p;
 }
 
-
 StubCodeDesc* StubCodeDesc::desc_for_index(int index) {
   StubCodeDesc* p = _list;
   while (p != NULL && p->index() != index) p = p->_next;
   return p;
 }
 
-
 const char* StubCodeDesc::name_for(address pc) {
   StubCodeDesc* p = desc_for(pc);
   return p == NULL ? NULL : p->name();
 }
 
 
+void StubCodeDesc::freeze() {
+  assert(!_frozen, "repeated freeze operation");
+  _frozen = true;
+}
+
 void StubCodeDesc::print_on(outputStream* st) const {
   st->print("%s", group());
   st->print("::");
@@ -110,12 +113,10 @@
   }
 }
 
-
 void StubCodeGenerator::stub_prolog(StubCodeDesc* cdesc) {
   // default implementation - do nothing
 }
 
-
 void StubCodeGenerator::stub_epilog(StubCodeDesc* cdesc) {
   // default implementation - record the cdesc
   if (_first_stub == NULL)  _first_stub = cdesc;
--- a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -28,7 +28,7 @@
 #include "asm/assembler.hpp"
 #include "memory/allocation.hpp"
 
-// All the basic framework for stubcode generation/debugging/printing.
+// All the basic framework for stub code generation/debugging/printing.
 
 
 // A StubCodeDesc describes a piece of generated code (usually stubs).
@@ -37,9 +37,10 @@
 // this may have to change if searching becomes too slow.
 
 class StubCodeDesc: public CHeapObj<mtCode> {
- protected:
+ private:
   static StubCodeDesc* _list;                  // the list of all descriptors
   static int           _count;                 // length of list
+  static bool          _frozen;                // determines whether _list modifications are allowed
 
   StubCodeDesc*        _next;                  // the next element in the linked list
   const char*          _group;                 // the group to which the stub code belongs
@@ -68,6 +69,7 @@
   static const char*   name_for(address pc);     // returns the name of the code containing pc or NULL
 
   StubCodeDesc(const char* group, const char* name, address begin, address end = NULL) {
+    assert(!_frozen, "no modifications allowed");
     assert(name != NULL, "no name specified");
     _next           = _list;
     _group          = group;
@@ -78,6 +80,8 @@
     _list           = this;
   };
 
+  static void freeze();
+
   const char* group() const                      { return _group; }
   const char* name() const                       { return _name; }
   int         index() const                      { return _index; }
@@ -117,7 +121,7 @@
 // later via an address pointing into it.
 
 class StubCodeMark: public StackObj {
- protected:
+ private:
   StubCodeGenerator* _cgen;
   StubCodeDesc*      _cdesc;
 
--- a/hotspot/src/share/vm/runtime/thread.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -3600,6 +3600,9 @@
     vm_exit_during_initialization("Failed to initialize tracing backend");
   }
 
+  // No more stub generation allowed after that point.
+  StubCodeDesc::freeze();
+
   // Set flag that basic initialization has completed. Used by exceptions and various
   // debug stuff, that does not work until all basic classes have been initialized.
   set_init_completed();
--- a/hotspot/src/share/vm/trace/trace.xml	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/trace/trace.xml	Wed Jul 05 21:24:14 2017 +0200
@@ -283,6 +283,7 @@
       <value type="BYTES64" field="edenUsedSize" label="Eden Used Size" />
       <value type="BYTES64" field="edenTotalSize" label="Eden Total Size" />
       <value type="BYTES64" field="survivorUsedSize" label="Survivor Used Size" />
+      <value type="UINT" field="numberOfRegions" label="Number of Regions" />
     </event>
 
     <event id="GCGarbageCollection" path="vm/gc/collector/garbage_collection" label="Garbage Collection"
@@ -478,6 +479,23 @@
       <value type="BYTES64" field="size" label="Allocation Size" />
     </event>
 
+    <event id="TenuringDistribution" path="vm/gc/detailed/tenuring_distribution" label="Tenuring Distribution"
+           is_instant="true">
+      <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+      <value type="UINT" field="age" label="Age" />
+      <value type="BYTES64" field="size" label="Size" />
+    </event>
+
+    <event id="G1HeapRegionTypeChange" path="vm/gc/detailed/g1_heap_region_type_change" label="G1 Heap Region Type Change"
+           description="Information about a G1 heap region type change." is_instant="true">
+      <value type="UINT" field="index" label="Index" />
+      <value type="G1HEAPREGIONTYPE" field="from" label="From Type" />
+      <value type="G1HEAPREGIONTYPE" field="to" label="To Type" />
+      <value type="ADDRESS" field="start" label="Start" />
+      <value type="BYTES64" field="used" label="Used" />
+      <value type="UINT" field="allocContext" label="Allocation Context" />
+    </event>
+
     <!-- Compiler events -->
 
     <event id="Compilation" path="vm/compiler/compilation" label="Compilation"
--- a/hotspot/src/share/vm/trace/tracetypes.xml	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/trace/tracetypes.xml	Wed Jul 05 21:24:14 2017 +0200
@@ -126,6 +126,11 @@
       <value type="UTF8" field="when" label="when" />
     </content_type>
 
+    <content_type id="G1HeapRegionType" hr_name="G1 Heap Region Type"
+                  type="U1" jvm_type="G1HEAPREGIONTYPE">
+      <value type="UTF8" field="type" label="type" />
+    </content_type>
+    
     <content_type id="G1YCType" hr_name="G1 YC Type"
                   type="U1" jvm_type="G1YCTYPE">
       <value type="UTF8" field="type" label="type" />
@@ -345,6 +350,10 @@
     <primary_type symbol="GCWHEN" datatype="U1" contenttype="GCWHEN"
                   type="u1" sizeop="sizeof(u1)" />
 
+    <!-- G1HEAPREGIONTYPE -->
+    <primary_type symbol="G1HEAPREGIONTYPE" datatype="U1" contenttype="G1HEAPREGIONTYPE"
+                  type="u1" sizeop="sizeof(u1)" />
+
     <!-- G1YCType -->
     <primary_type symbol="G1YCTYPE" datatype="U1" contenttype="G1YCTYPE"
                   type="u1" sizeop="sizeof(u1)" />
--- a/hotspot/src/share/vm/utilities/copy.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/utilities/copy.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -53,6 +53,175 @@
   }
 }
 
+class CopySwap : AllStatic {
+public:
+  /**
+   * Copy and byte swap elements
+   *
+   * @param src address of source
+   * @param dst address of destination
+   * @param byte_count number of bytes to copy
+   * @param elem_size size of the elements to copy-swap
+   */
+  static void conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
+    assert(src != NULL, "address must not be NULL");
+    assert(dst != NULL, "address must not be NULL");
+    assert(elem_size == 2 || elem_size == 4 || elem_size == 8,
+           "incorrect element size: " SIZE_FORMAT, elem_size);
+    assert(is_size_aligned(byte_count, elem_size),
+           "byte_count " SIZE_FORMAT " must be multiple of element size " SIZE_FORMAT, byte_count, elem_size);
+
+    address src_end = src + byte_count;
+
+    if (dst <= src || dst >= src_end) {
+      do_conjoint_swap<RIGHT>(src, dst, byte_count, elem_size);
+    } else {
+      do_conjoint_swap<LEFT>(src, dst, byte_count, elem_size);
+    }
+  }
+
+private:
+  /**
+   * Byte swap a 16-bit value
+   */
+  static uint16_t byte_swap(uint16_t x) {
+    return (x << 8) | (x >> 8);
+  }
+
+  /**
+   * Byte swap a 32-bit value
+   */
+  static uint32_t byte_swap(uint32_t x) {
+    uint16_t lo = (uint16_t)x;
+    uint16_t hi = (uint16_t)(x >> 16);
+
+    return ((uint32_t)byte_swap(lo) << 16) | (uint32_t)byte_swap(hi);
+  }
+
+  /**
+   * Byte swap a 64-bit value
+   */
+  static uint64_t byte_swap(uint64_t x) {
+    uint32_t lo = (uint32_t)x;
+    uint32_t hi = (uint32_t)(x >> 32);
+
+    return ((uint64_t)byte_swap(lo) << 32) | (uint64_t)byte_swap(hi);
+  }
+
+  enum CopyDirection {
+    RIGHT, // lower -> higher address
+    LEFT   // higher -> lower address
+  };
+
+  /**
+   * Copy and byte swap elements
+   *
+   * <T> - type of element to copy
+   * <D> - copy direction
+   * <is_src_aligned> - true if src argument is aligned to element size
+   * <is_dst_aligned> - true if dst argument is aligned to element size
+   *
+   * @param src address of source
+   * @param dst address of destination
+   * @param byte_count number of bytes to copy
+   */
+  template <typename T, CopyDirection D, bool is_src_aligned, bool is_dst_aligned>
+  static void do_conjoint_swap(address src, address dst, size_t byte_count) {
+    address cur_src, cur_dst;
+
+    switch (D) {
+    case RIGHT:
+      cur_src = src;
+      cur_dst = dst;
+      break;
+    case LEFT:
+      cur_src = src + byte_count - sizeof(T);
+      cur_dst = dst + byte_count - sizeof(T);
+      break;
+    }
+
+    for (size_t i = 0; i < byte_count / sizeof(T); i++) {
+      T tmp;
+
+      if (is_src_aligned) {
+        tmp = *(T*)cur_src;
+      } else {
+        memcpy(&tmp, cur_src, sizeof(T));
+      }
+
+      tmp = byte_swap(tmp);
+
+      if (is_dst_aligned) {
+        *(T*)cur_dst = tmp;
+      } else {
+        memcpy(cur_dst, &tmp, sizeof(T));
+      }
+
+      switch (D) {
+      case RIGHT:
+        cur_src += sizeof(T);
+        cur_dst += sizeof(T);
+        break;
+      case LEFT:
+        cur_src -= sizeof(T);
+        cur_dst -= sizeof(T);
+        break;
+      }
+    }
+  }
+
+  /**
+   * Copy and byte swap elements
+   *
+   * <T> - type of element to copy
+   * <D> - copy direction
+   *
+   * @param src address of source
+   * @param dst address of destination
+   * @param byte_count number of bytes to copy
+   */
+  template <typename T, CopyDirection direction>
+  static void do_conjoint_swap(address src, address dst, size_t byte_count) {
+    if (is_ptr_aligned(src, sizeof(T))) {
+      if (is_ptr_aligned(dst, sizeof(T))) {
+        do_conjoint_swap<T,direction,true,true>(src, dst, byte_count);
+      } else {
+        do_conjoint_swap<T,direction,true,false>(src, dst, byte_count);
+      }
+    } else {
+      if (is_ptr_aligned(dst, sizeof(T))) {
+        do_conjoint_swap<T,direction,false,true>(src, dst, byte_count);
+      } else {
+        do_conjoint_swap<T,direction,false,false>(src, dst, byte_count);
+      }
+    }
+  }
+
+
+  /**
+   * Copy and byte swap elements
+   *
+   * <D> - copy direction
+   *
+   * @param src address of source
+   * @param dst address of destination
+   * @param byte_count number of bytes to copy
+   * @param elem_size size of the elements to copy-swap
+   */
+  template <CopyDirection D>
+  static void do_conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
+    switch (elem_size) {
+    case 2: do_conjoint_swap<uint16_t,D>(src, dst, byte_count); break;
+    case 4: do_conjoint_swap<uint32_t,D>(src, dst, byte_count); break;
+    case 8: do_conjoint_swap<uint64_t,D>(src, dst, byte_count); break;
+    default: guarantee(false, "do_conjoint_swap: Invalid elem_size %zd\n", elem_size);
+    }
+  }
+};
+
+void Copy::conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
+  CopySwap::conjoint_swap(src, dst, byte_count, elem_size);
+}
 
 // Fill bytes; larger units are filled atomically if everything is aligned.
 void Copy::fill_to_memory_atomic(void* to, size_t size, jubyte value) {
--- a/hotspot/src/share/vm/utilities/copy.hpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/utilities/copy.hpp	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, 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
@@ -227,6 +227,16 @@
     }
   }
 
+  /**
+   * Copy and *unconditionally* byte swap elements
+   *
+   * @param src address of source
+   * @param dst address of destination
+   * @param byte_count number of bytes to copy
+   * @param elem_size size of the elements to copy-swap
+   */
+  static void conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size);
+
   // Fill methods
 
   // Fill word-aligned words, not atomic on each word
--- a/hotspot/src/share/vm/utilities/quickSort.cpp	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/src/share/vm/utilities/quickSort.cpp	Wed Jul 05 21:24:14 2017 +0200
@@ -44,6 +44,31 @@
   }
   return 1;
 }
+
+static void print_array(const char* prefix, int* array, int length) {
+  tty->print("%s:", prefix);
+  for (int i = 0; i < length; i++) {
+    tty->print(" %d", array[i]);
+  }
+  tty->cr();
+}
+
+static bool compare_arrays(int* actual, int* expected, int length) {
+  for (int i = 0; i < length; i++) {
+    if (actual[i] != expected[i]) {
+      print_array("Sorted array  ", actual, length);
+      print_array("Expected array", expected, length);
+      return false;
+    }
+  }
+  return true;
+}
+
+template <class C>
+static bool sort_and_compare(int* arrayToSort, int* expectedResult, int length, C comparator, bool idempotent = false) {
+  QuickSort::sort<int, C>(arrayToSort, length, comparator, idempotent);
+  return compare_arrays(arrayToSort, expectedResult, length);
+}
 #endif // ASSERT
 
 static int test_even_odd_comparator(int a, int b) {
@@ -72,31 +97,6 @@
   }
 }
 
-static void print_array(const char* prefix, int* array, int length) {
-  tty->print("%s:", prefix);
-  for (int i = 0; i < length; i++) {
-    tty->print(" %d", array[i]);
-  }
-  tty->cr();
-}
-
-static bool compare_arrays(int* actual, int* expected, int length) {
-  for (int i = 0; i < length; i++) {
-    if (actual[i] != expected[i]) {
-      print_array("Sorted array  ", actual, length);
-      print_array("Expected array", expected, length);
-      return false;
-    }
-  }
-  return true;
-}
-
-template <class C>
-static bool sort_and_compare(int* arrayToSort, int* expectedResult, int length, C comparator, bool idempotent = false) {
-  QuickSort::sort<int, C>(arrayToSort, length, comparator, idempotent);
-  return compare_arrays(arrayToSort, expectedResult, length);
-}
-
 void QuickSort_test() {
   {
     int* test_array = NULL;
--- a/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java	Wed Jul 05 21:24:14 2017 +0200
@@ -33,9 +33,10 @@
  *
  * @run main/othervm
  *        -Xbootclasspath/a:.
+ *        -Xmixed
  *        -XX:+UnlockDiagnosticVMOptions
  *        -XX:+WhiteBoxAPI
- *        -XX:MaxInlineSize=100
+ *        -XX:MaxInlineSize=70
  *        -XX:MinInliningThreshold=0
  *        TestStringIntrinsics2
  */
--- a/hotspot/test/compiler/loopopts/superword/ProdRed_Double.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Double.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
  * @test
  * @bug 8074981
  * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Double
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Double
--- a/hotspot/test/compiler/loopopts/superword/ProdRed_Float.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Float.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
  * @test
  * @bug 8074981
  * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Float
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Float
--- a/hotspot/test/compiler/loopopts/superword/ProdRed_Int.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Int.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
  * @test
  * @bug 8074981
  * @summary Add C2 x86 Superword support for scalar product reduction optimizations : int test
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Int
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Int
--- a/hotspot/test/compiler/loopopts/superword/ReductionPerf.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/ReductionPerf.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
  * @test
  * @bug 8074981
  * @summary Add C2 x86 Superword support for scalar product reduction optimizations : int test
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:CompileThresholdScaling=0.1 -XX:CompileCommand=exclude,ReductionPerf::main ReductionPerf
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:CompileThresholdScaling=0.1 -XX:CompileCommand=exclude,ReductionPerf::main ReductionPerf
--- a/hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,7 +26,7 @@
 * @test
 * @bug 8135028
 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double sqrt test
-* @requires os.arch=="x86" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
+* @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
 *
 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedSqrt_Double
 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedSqrt_Double
--- a/hotspot/test/compiler/loopopts/superword/SumRed_Double.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/SumRed_Double.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
  * @test
  * @bug 8074981
  * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double test
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Double
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Double
--- a/hotspot/test/compiler/loopopts/superword/SumRed_Float.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/SumRed_Float.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
  * @test
  * @bug 8074981
  * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : float test
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Float
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Float
--- a/hotspot/test/compiler/loopopts/superword/SumRed_Int.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/SumRed_Int.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
  * @test
  * @bug 8074981
  * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : int test
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Int
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Int
--- a/hotspot/test/compiler/loopopts/superword/SumRed_Long.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/compiler/loopopts/superword/SumRed_Long.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
  * @test
  * @bug 8076276
  * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : long test
+ * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64"
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Long
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Long
--- a/hotspot/test/runtime/CommandLine/VMDeprecatedOptions.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/hotspot/test/runtime/CommandLine/VMDeprecatedOptions.java	Wed Jul 05 21:24:14 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
@@ -40,6 +40,8 @@
         // deprecated non-alias flags:
         {"MaxGCMinorPauseMillis", "1032"},
         {"UseParNewGC", "false"},
+        {"ConvertSleepToYield", "false" },
+        {"ConvertYieldToSleep", "false" },
 
         // deprecated alias flags (see also aliased_jvm_flags):
         {"DefaultMaxRAMFraction", "4"},
--- a/jaxp/.hgtags	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/.hgtags	Wed Jul 05 21:24:14 2017 +0200
@@ -349,3 +349,4 @@
 58448465334e1d8bf1cfc09052783937b1cc21c0 jdk-9+104
 5acf6071d4d610068a19c79e004ba8e59cf1b087 jdk-9+105
 65d615f71e81bae46dcb4d053e590582e5705879 jdk-9+106
+781b83dadcae89b8ae7545bb4044ddc62c6fa006 jdk-9+107
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DTDScannerImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DTDScannerImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -97,19 +97,9 @@
 public class XML11DTDScannerImpl
     extends XMLDTDScannerImpl {
 
-    /** Array of 3 strings. */
-    private String[] fStrings = new String[3];
-
-    /** String. */
-    private XMLString fString = new XMLString();
-
     /** String buffer. */
     private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
 
-    /** String buffer. */
-    private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
-    private XMLStringBuffer fStringBuffer3 = new XMLStringBuffer();
-
     //
     // Constructors
     //
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java	Wed Jul 05 21:24:14 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.
  */
 
 /*
@@ -46,7 +46,6 @@
 import com.sun.org.apache.xerces.internal.impl.Constants;
 import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
-import com.sun.xml.internal.stream.Entity;
 
 /**
  * This class is responsible for scanning the declarations found
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Wed Jul 05 21:24:14 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.
  */
 
 /*
@@ -23,7 +23,6 @@
 
 import com.sun.xml.internal.stream.XMLBufferListener;
 import com.sun.xml.internal.stream.XMLEntityStorage;
-import com.sun.xml.internal.stream.XMLInputFactoryImpl;
 import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
 
 import java.io.EOFException;
@@ -50,17 +49,11 @@
 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.util.NamespaceSupport;
 import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
-import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
 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.XMLSecurityManager.State;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
-import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
-import javax.xml.XMLConstants;
 import javax.xml.stream.XMLStreamConstants;
-import javax.xml.stream.events.XMLEvent;
 
 /**
  *
@@ -210,12 +203,12 @@
                 null,
                 null,
                 null,
-                EXTERNAL_ACCESS_DEFAULT
+                null
     };
 
     private static final char [] cdata = {'[','C','D','A','T','A','['};
     static final char [] xmlDecl = {'<','?','x','m','l'};
-    private static final char [] endTag = {'<','/'};
+    // private static final char [] endTag = {'<','/'};
     // debugging
 
     /** Debug scanner state. */
@@ -2066,7 +2059,7 @@
      */
     String checkAccess(String systemId, String allowedProtocols) throws IOException {
         String baseSystemId = fEntityScanner.getBaseSystemId();
-        String expandedSystemId = fEntityManager.expandSystemId(systemId, baseSystemId,fStrictURI);
+        String expandedSystemId = XMLEntityManager.expandSystemId(systemId, baseSystemId, fStrictURI);
         return SecuritySupport.checkAccess(expandedSystemId, allowedProtocols, Constants.ACCESS_EXTERNAL_ALL);
     }
 
@@ -2602,8 +2595,6 @@
         //
         // Driver methods
         //
-        private boolean fContinueDispatching = true;
-        private boolean fScanningForMarkup = true;
 
         /**
          *  decides the appropriate state of the parser
@@ -3266,7 +3257,7 @@
 
     protected XMLString getString(){
         if(fAttributeCacheUsedCount < initialCacheCount || fAttributeCacheUsedCount < attributeValueCache.size()){
-            return (XMLString)attributeValueCache.get(fAttributeCacheUsedCount++);
+            return attributeValueCache.get(fAttributeCacheUsedCount++);
         } else{
             XMLString str = new XMLString();
             fAttributeCacheUsedCount++;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java	Wed Jul 05 21:24:14 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.
  */
 
 /*
@@ -31,7 +31,6 @@
 import com.sun.org.apache.xerces.internal.xni.Augmentations;
 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
-import com.sun.org.apache.xerces.internal.xni.XMLString;
 import com.sun.org.apache.xerces.internal.xni.XNIException;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
@@ -224,9 +223,6 @@
     /** A DTD Description. */
     private final XMLDTDDescription fDTDDescription = new XMLDTDDescription(null, null, null, null, null);
 
-    /** String. */
-    private XMLString fString = new XMLString();
-
     private static final char [] DOCTYPE = {'D','O','C','T','Y','P','E'};
     private static final char [] COMMENTSTRING = {'-','-'};
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java	Wed Jul 05 21:24:14 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.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -370,7 +370,7 @@
     protected Map<String, Entity> fEntities = new HashMap<>();
 
     /** Entity stack. */
-    protected Stack fEntityStack = new Stack();
+    protected Stack<Entity> fEntityStack = new Stack<>();
 
     /** Current entity. */
     protected Entity.ScannedEntity fCurrentEntity = null;
@@ -633,10 +633,10 @@
                         final HTTPInputSource httpInputSource = (HTTPInputSource) xmlInputSource;
 
                         // set request properties
-                        Iterator propIter = httpInputSource.getHTTPRequestProperties();
+                        Iterator<Map.Entry<String, String>> propIter = httpInputSource.getHTTPRequestProperties();
                         while (propIter.hasNext()) {
-                            Map.Entry entry = (Map.Entry) propIter.next();
-                            urlConnection.setRequestProperty((String) entry.getKey(), (String) entry.getValue());
+                            Map.Entry<String, String> entry = propIter.next();
+                            urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
                         }
 
                         // set preference for redirection
@@ -1057,7 +1057,6 @@
         String literalSystemId = resourceIdentifier.getLiteralSystemId();
         String baseSystemId = resourceIdentifier.getBaseSystemId();
         String expandedSystemId = resourceIdentifier.getExpandedSystemId();
-        String namespace = resourceIdentifier.getNamespace();
 
         // if no base systemId given, assume that it's relative
         // to the systemId of the current scanned entity
@@ -2067,14 +2066,6 @@
 
         // system id has to be a valid URI
         if (strict) {
-
-
-            // check if there is a system id before
-            // trying to expand it.
-            if (systemId == null) {
-                return null;
-            }
-
             try {
                 // if it's already an absolute one, return it
                 new URI(systemId);
@@ -2968,7 +2959,7 @@
                     if (!fCurrentEntity.xmlDeclChunkRead)
                     {
                         fCurrentEntity.xmlDeclChunkRead = true;
-                        len = fCurrentEntity.DEFAULT_XMLDECL_BUFFER_SIZE;
+                        len = Entity.ScannedEntity.DEFAULT_XMLDECL_BUFFER_SIZE;
                     }
                     return fInputStream.read(b, off, len);
                 }
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java	Wed Jul 05 21:24:14 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.
  */
 
 /*
@@ -25,8 +25,6 @@
 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidatorFilter;
 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
-import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
-import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
 import com.sun.org.apache.xerces.internal.xni.QName;
@@ -34,13 +32,9 @@
 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
-import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
-import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
 
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.events.XMLEvent;
 
 /**
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java	Wed Jul 05 21:24:14 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.
  */
 
 /*
@@ -25,7 +25,6 @@
 import com.sun.xml.internal.stream.XMLEntityStorage;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import javax.xml.stream.events.XMLEvent;
 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
 import com.sun.org.apache.xerces.internal.util.SymbolTable;
@@ -120,8 +119,8 @@
     //we should have a feature when set to true computes this value
     private boolean fNeedNonNormalizedValue = false;
 
-    protected ArrayList attributeValueCache = new ArrayList();
-    protected ArrayList stringBufferCache = new ArrayList();
+    protected ArrayList<XMLString> attributeValueCache = new ArrayList<>();
+    protected ArrayList<XMLStringBuffer> stringBufferCache = new ArrayList<>();
     protected int fStringBufferIndex = 0;
     protected boolean fAttributeCacheInitDone = false;
     protected int fAttributeCacheUsedCount = 0;
@@ -1470,7 +1469,7 @@
 
     XMLStringBuffer getStringBuffer(){
         if((fStringBufferIndex < initialCacheCount )|| (fStringBufferIndex < stringBufferCache.size())){
-            return (XMLStringBuffer)stringBufferCache.get(fStringBufferIndex++);
+            return stringBufferCache.get(fStringBufferIndex++);
         }else{
             XMLStringBuffer tmpObj = new XMLStringBuffer();
             fStringBufferIndex++;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSAttributeChecker.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSAttributeChecker.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -1172,7 +1172,7 @@
             if (max != SchemaSymbols.OCCURRENCE_UNBOUNDED) {
 
                 // maxOccurLimit is only check in secure mode
-                if (fSchemaHandler.fSecureProcessing != null) {
+                if (fSchemaHandler.fSecurityManager != null) {
                     String localName = element.getLocalName();
 
                 // The maxOccurs restriction no longer applies to elements
@@ -1191,8 +1191,8 @@
                     if (!optimize) {
                     //Revisit :: IMO this is not right place to check
                     // maxOccurNodeLimit.
-                    int maxOccurNodeLimit = fSchemaHandler.fSecureProcessing.getLimit(XMLSecurityManager.Limit.MAX_OCCUR_NODE_LIMIT);
-                    if (max > maxOccurNodeLimit && !fSchemaHandler.fSecureProcessing.isNoLimit(maxOccurNodeLimit)) {
+                    int maxOccurNodeLimit = fSchemaHandler.fSecurityManager.getLimit(XMLSecurityManager.Limit.MAX_OCCUR_NODE_LIMIT);
+                    if (max > maxOccurNodeLimit && !fSchemaHandler.fSecurityManager.isNoLimit(maxOccurNodeLimit)) {
                         reportSchemaFatalError("MaxOccurLimit", new Object[] {new Integer(maxOccurNodeLimit)}, element);
 
                         // reset max values in case processing continues on error
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -194,6 +194,7 @@
     /** Property identifier: entity resolver. */
     public static final String ENTITY_RESOLVER =
         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
+
     /** Property identifier: entity manager. */
     protected static final String ENTITY_MANAGER =
         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
@@ -214,16 +215,13 @@
     protected static final String SECURITY_MANAGER =
         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 
-    private static final String SECURE_PROCESSING =
-        Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
-
     /** Property identifier: locale. */
     protected static final String LOCALE =
         Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY;
 
-        /** Property identifier: Security property manager. */
+    /** Property identifier: Security property manager. */
     private static final String XML_SECURITY_PROPERTY_MANAGER =
-            Constants.XML_SECURITY_PROPERTY_MANAGER;
+        Constants.XML_SECURITY_PROPERTY_MANAGER;
 
     protected static final boolean DEBUG_NODE_POOL = false;
 
@@ -243,17 +241,12 @@
     // as unlikely as possible to cause collisions.
     public final static String REDEF_IDENTIFIER = "_fn3dktizrknc9pi";
 
-    //
-    //protected data that can be accessable by any traverser
+    //protected data that can be accessible by any traverser
 
     protected XSDeclarationPool fDeclPool = null;
 
-    /**
-     * <p>Security manager in effect.</p>
-     *
-     * <p>Protected to allow access by any traverser.</p>
-     */
-    protected XMLSecurityManager fSecureProcessing = null;
+    // the Security manager in effect.
+    protected XMLSecurityManager fSecurityManager = null;
 
     private String fAccessExternalSchema;
     private String fAccessExternalDTD;
@@ -266,27 +259,28 @@
     // XSDocumentInfoRegistry we can easily get the corresponding
     // XSDocumentInfo object.
     private boolean registryEmpty = true;
-    private Map<String, Element> fUnparsedAttributeRegistry = new HashMap();
-    private Map<String, Element> fUnparsedAttributeGroupRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedElementRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedGroupRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedIdentityConstraintRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedNotationRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedTypeRegistry =  new HashMap();
+    private Map<String, Element> fUnparsedAttributeRegistry = new HashMap<>();
+    private Map<String, Element> fUnparsedAttributeGroupRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedElementRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedGroupRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedIdentityConstraintRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedNotationRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedTypeRegistry =  new HashMap<>();
     // Compensation for the above maps to locate XSDocumentInfo,
     // Since we may take Schema Element directly, so can not get the
     // corresponding XSDocumentInfo object just using above maps.
-    private Map<String, XSDocumentInfo> fUnparsedAttributeRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedAttributeGroupRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedElementRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedGroupRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedIdentityConstraintRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedNotationRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedTypeRegistrySub =  new HashMap();
+    private Map<String, XSDocumentInfo> fUnparsedAttributeRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedAttributeGroupRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedElementRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedGroupRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedIdentityConstraintRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedNotationRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedTypeRegistrySub =  new HashMap<>();
 
     // Stores XSDocumentInfo (keyed by component name), to check for duplicate
     // components declared within the same xsd document
-    private Map fUnparsedRegistriesExt[] = new HashMap[] {
+    @SuppressWarnings("unchecked")
+    private Map<String, XSDocumentInfo> fUnparsedRegistriesExt[] = new HashMap[] {
         null,
         null, // ATTRIBUTE_TYPE
         null, // ATTRIBUTEGROUP_TYPE
@@ -300,17 +294,19 @@
     // this map is keyed on by XSDocumentInfo objects.  Its values
     // are Vectors containing the XSDocumentInfo objects <include>d,
     // <import>ed or <redefine>d by the key XSDocumentInfo.
-    private Map<XSDocumentInfo, Vector> fDependencyMap = new HashMap();
+    private Map<XSDocumentInfo, Vector<XSDocumentInfo>> fDependencyMap = new HashMap<>();
 
     // this map is keyed on by a target namespace.  Its values
     // are Vectors containing namespaces imported by schema documents
     // with the key target namespace.
-    // if an imprted schema has absent namespace, the value "null" is stored.
-    private Map<String, Vector> fImportMap = new HashMap();
+    // if an imported schema has absent namespace, the value "null" is stored.
+    private Map<String, Vector> fImportMap = new HashMap<> ();
+
     // all namespaces that imports other namespaces
     // if the importing schema has absent namespace, empty string is stored.
     // (because the key of a map can't be null.)
-    private Vector fAllTNSs = new Vector();
+    private Vector<String> fAllTNSs = new Vector<>();
+
     // stores instance document mappings between namespaces and schema hints
     private Map<String, XMLSchemaLoader.LocationArray> fLocationPairs = null;
 
@@ -333,7 +329,7 @@
         if(ele.getOwnerDocument() instanceof com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOM){
             documentURI = ((com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOM) ele.getOwnerDocument()).getDocumentURI();
         }
-        return documentURI != null ? documentURI : (String) fDoc2SystemId.get(ele);
+        return documentURI != null ? documentURI : fDoc2SystemId.get(ele);
     }
 
     // This vector stores strings which are combinations of the
@@ -341,11 +337,11 @@
     // schema document.  This combination is used so that the user's
     // EntityResolver can provide a consistent way of identifying a
     // schema document that is included in multiple other schemas.
-    private Map fTraversed = new HashMap();
+    private Map<XSDKey, Element> fTraversed = new HashMap<>();
 
     // this map contains a mapping from Schema Element to its systemId
     // this is useful to resolve a uri relative to the referring document
-    private Map fDoc2SystemId = new HashMap();
+    private Map<Element, String> fDoc2SystemId = new HashMap<>();
 
     // the primary XSDocumentInfo we were called to parse
     private XSDocumentInfo fRoot = null;
@@ -387,7 +383,15 @@
 
     // the XMLErrorReporter
     private XMLErrorReporter fErrorReporter;
-    private XMLEntityResolver fEntityResolver;
+
+    // the XMLErrorHandler
+    private XMLErrorHandler fErrorHandler;
+
+    // the Locale
+    private Locale fLocale;
+
+    // the XMLEntityManager
+    private XMLEntityResolver fEntityManager;
 
     // the XSAttributeChecker
     private XSAttributeChecker fAttributeChecker;
@@ -404,6 +408,9 @@
     // the Grammar Pool
     private XMLGrammarPool fGrammarPool;
 
+    // the security property manager
+    private XMLSecurityPropertyManager fSecurityPropertyMgr = null;
+
     //************ Traversers **********
     XSDAttributeGroupTraverser fAttributeGroupTraverser;
     XSDAttributeTraverser fAttributeTraverser;
@@ -638,7 +645,7 @@
         // for all grammars with <import>s
         for (int i = fAllTNSs.size() - 1; i >= 0; i--) {
             // get its target namespace
-            String tns = (String)fAllTNSs.elementAt(i);
+            String tns = fAllTNSs.elementAt(i);
             // get all namespaces it imports
             Vector ins = (Vector)fImportMap.get(tns);
             // get the grammar
@@ -696,12 +703,13 @@
         fAnnotationValidator.setFeature(VALIDATION, true);
         fAnnotationValidator.setFeature(XMLSCHEMA_VALIDATION, true);
         fAnnotationValidator.setProperty(XMLGRAMMAR_POOL, fGrammarBucketAdapter);
+        /** set security manager and XML Security Property Manager **/
+        fAnnotationValidator.setProperty(SECURITY_MANAGER, (fSecurityManager != null) ? fSecurityManager : new XMLSecurityManager(true));
+        fAnnotationValidator.setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
         /** Set error handler. **/
-        XMLErrorHandler errorHandler = fErrorReporter.getErrorHandler();
-        fAnnotationValidator.setProperty(ERROR_HANDLER, (errorHandler != null) ? errorHandler : new DefaultErrorHandler());
+        fAnnotationValidator.setProperty(ERROR_HANDLER, (fErrorHandler != null) ? fErrorHandler : new DefaultErrorHandler());
         /** Set locale. **/
-        Locale locale = fErrorReporter.getLocale();
-        fAnnotationValidator.setProperty(LOCALE, locale);
+        fAnnotationValidator.setProperty(LOCALE, fLocale);
     }
 
     /**
@@ -880,10 +888,10 @@
 
         // store the document and its location
         // REVISIT: don't expose the DOM tree
-        sg.addDocument(null, (String)fDoc2SystemId.get(currSchemaInfo.fSchemaElement));
+        sg.addDocument(null, fDoc2SystemId.get(currSchemaInfo.fSchemaElement));
 
         fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo);
-        Vector dependencies = new Vector();
+        Vector<XSDocumentInfo> dependencies = new Vector<>();
         Element rootNode = schemaRoot;
 
         Element newSchemaRoot = null;
@@ -1334,9 +1342,9 @@
             } // end for
 
             // now we're done with this one!
-                DOMUtil.setHidden(currDoc, fHiddenNodes);
+            DOMUtil.setHidden(currDoc, fHiddenNodes);
             // now add the schemas this guy depends on
-            Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
+            Vector<XSDocumentInfo> currSchemaDepends = fDependencyMap.get(currSchemaDoc);
             for (int i = 0; i < currSchemaDepends.size(); i++) {
                 schemasToProcess.push(currSchemaDepends.elementAt(i));
             }
@@ -1466,7 +1474,7 @@
             DOMUtil.setHidden(currDoc, fHiddenNodes);
 
             // now add the schemas this guy depends on
-            Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
+            Vector<XSDocumentInfo> currSchemaDepends = fDependencyMap.get(currSchemaDoc);
             for (int i = 0; i < currSchemaDepends.size(); i++) {
                 schemasToProcess.push(currSchemaDepends.elementAt(i));
             }
@@ -1915,7 +1923,7 @@
     }
 
     public String schemaDocument2SystemId(XSDocumentInfo schemaDoc) {
-        return (String)fDoc2SystemId.get(schemaDoc.fSchemaElement);
+        return fDoc2SystemId.get(schemaDoc.fSchemaElement);
     }
 
     // This method determines whether there is a group
@@ -2044,7 +2052,7 @@
         XMLInputSource schemaSource = null;
         try {
             Map<String, XMLSchemaLoader.LocationArray> pairs = usePairs ? fLocationPairs : Collections.emptyMap();
-            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityResolver);
+            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityManager);
         }
         catch (IOException ex) {
             if (mustResolve) {
@@ -2097,7 +2105,7 @@
         XMLInputSource schemaSource = null;
         try {
             Map<String, XMLSchemaLoader.LocationArray> pairs = usePairs ? fLocationPairs : Collections.emptyMap();
-            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityResolver);
+            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityManager);
         }
         catch (IOException ex) {
             if (mustResolve) {
@@ -2152,7 +2160,7 @@
                 if (referType != XSDDescription.CONTEXT_PREPARSE){
                     schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId(), false);
                     key = new XSDKey(schemaId, referType, schemaNamespace);
-                    if((schemaElement = (Element)fTraversed.get(key)) != null) {
+                    if((schemaElement = fTraversed.get(key)) != null) {
                         fLastSchemaWasDuplicate = true;
                         return schemaElement;
                     }
@@ -2211,7 +2219,7 @@
                 if (referType != XSDDescription.CONTEXT_PREPARSE) {
                     schemaId = XMLEntityManager.expandSystemId(inputSource.getSystemId(), schemaSource.getBaseSystemId(), false);
                     key = new XSDKey(schemaId, referType, schemaNamespace);
-                    if ((schemaElement = (Element) fTraversed.get(key)) != null) {
+                    if ((schemaElement = fTraversed.get(key)) != null) {
                         fLastSchemaWasDuplicate = true;
                         return schemaElement;
                     }
@@ -2238,9 +2246,8 @@
                         namespacePrefixes = true;
                         // If this is a Xerces SAX parser set the security manager if there is one
                         if (parser instanceof SAXParser) {
-                            Object securityManager = fSchemaParser.getProperty(SECURITY_MANAGER);
-                            if (securityManager != null) {
-                                parser.setProperty(SECURITY_MANAGER, securityManager);
+                            if (fSecurityManager != null) {
+                                parser.setProperty(SECURITY_MANAGER, fSecurityManager);
                             }
                         }
                     }
@@ -2347,7 +2354,7 @@
                     }
                     if (isDocument) {
                         key = new XSDKey(schemaId, referType, schemaNamespace);
-                        if ((schemaElement = (Element) fTraversed.get(key)) != null) {
+                        if ((schemaElement = fTraversed.get(key)) != null) {
                             fLastSchemaWasDuplicate = true;
                             return schemaElement;
                         }
@@ -2402,7 +2409,7 @@
                 }
                 if (isDocument) {
                     key = new XSDKey(schemaId, referType, schemaNamespace);
-                    if ((schemaElement = (Element) fTraversed.get(key)) != null) {
+                    if ((schemaElement = fTraversed.get(key)) != null) {
                         fLastSchemaWasDuplicate = true;
                         return schemaElement;
                     }
@@ -3502,40 +3509,21 @@
         // set symbol table
         fSymbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
 
-        fSecureProcessing = null;
-        if( componentManager!=null ) {
-            fSecureProcessing = (XMLSecurityManager) componentManager.getProperty(SECURE_PROCESSING, null);
-        }
+        // set security manager
+        fSecurityManager = (XMLSecurityManager) componentManager.getProperty(SECURITY_MANAGER, null);
+
+        //set entity manager
+        fEntityManager = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
 
         //set entity resolver
-        fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
         XMLEntityResolver er = (XMLEntityResolver)componentManager.getProperty(ENTITY_RESOLVER);
         if (er != null)
             fSchemaParser.setEntityResolver(er);
 
         // set error reporter
-        fErrorReporter =
-            (XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER);
-        try {
-            XMLErrorHandler currErrorHandler = fErrorReporter.getErrorHandler();
-            // Setting a parser property can be much more expensive
-            // than checking its value.  Don't set the ERROR_HANDLER
-            // or LOCALE properties unless they've actually changed.
-            if (currErrorHandler != fSchemaParser.getProperty(ERROR_HANDLER)) {
-                fSchemaParser.setProperty(ERROR_HANDLER, (currErrorHandler != null) ? currErrorHandler : new DefaultErrorHandler());
-                if (fAnnotationValidator != null) {
-                    fAnnotationValidator.setProperty(ERROR_HANDLER, (currErrorHandler != null) ? currErrorHandler : new DefaultErrorHandler());
-                }
-            }
-            Locale currentLocale = fErrorReporter.getLocale();
-            if (currentLocale != fSchemaParser.getProperty(LOCALE)) {
-                fSchemaParser.setProperty(LOCALE, currentLocale);
-                if (fAnnotationValidator != null) {
-                    fAnnotationValidator.setProperty(LOCALE, currentLocale);
-                }
-            }
-        }
-        catch (XMLConfigurationException e) {}
+        fErrorReporter = (XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER);
+        fErrorHandler = fErrorReporter.getErrorHandler();
+        fLocale = fErrorReporter.getLocale();
 
         fValidateAnnotations = componentManager.getFeature(VALIDATE_ANNOTATIONS, false);
         fHonourAllSchemaLocations = componentManager.getFeature(HONOUR_ALL_SCHEMALOCATIONS, false);
@@ -3543,56 +3531,66 @@
         fTolerateDuplicates = componentManager.getFeature(TOLERATE_DUPLICATES, false);
 
         try {
-            fSchemaParser.setFeature(
-                    CONTINUE_AFTER_FATAL_ERROR,
-                    fErrorReporter.getFeature(CONTINUE_AFTER_FATAL_ERROR));
-        } catch (XMLConfigurationException e) {
+            // Setting a parser property can be much more expensive
+            // than checking its value.  Don't set the ERROR_HANDLER
+            // or LOCALE properties unless they've actually changed.
+            if (fErrorHandler != fSchemaParser.getProperty(ERROR_HANDLER)) {
+                fSchemaParser.setProperty(ERROR_HANDLER, (fErrorHandler != null) ? fErrorHandler : new DefaultErrorHandler());
+                if (fAnnotationValidator != null) {
+                    fAnnotationValidator.setProperty(ERROR_HANDLER, (fErrorHandler != null) ? fErrorHandler : new DefaultErrorHandler());
+                }
+            }
+            if (fLocale != fSchemaParser.getProperty(LOCALE)) {
+                fSchemaParser.setProperty(LOCALE, fLocale);
+                if (fAnnotationValidator != null) {
+                    fAnnotationValidator.setProperty(LOCALE, fLocale);
+                }
+            }
         }
+        catch (XMLConfigurationException e) {}
+
+        try {
+            fSchemaParser.setFeature(CONTINUE_AFTER_FATAL_ERROR, fErrorReporter.getFeature(CONTINUE_AFTER_FATAL_ERROR));
+        } catch (XMLConfigurationException e) {}
 
         try {
             if (componentManager.getFeature(ALLOW_JAVA_ENCODINGS, false)) {
                 fSchemaParser.setFeature(ALLOW_JAVA_ENCODINGS, true);
             }
-        } catch (XMLConfigurationException e) {
-        }
+        } catch (XMLConfigurationException e) {}
+
         try {
             if (componentManager.getFeature(STANDARD_URI_CONFORMANT_FEATURE, false)) {
                 fSchemaParser.setFeature(STANDARD_URI_CONFORMANT_FEATURE, true);
             }
-        } catch (XMLConfigurationException e) {
-        }
+        } catch (XMLConfigurationException e) {}
 
         try {
-            fGrammarPool =
-                (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL);
+            fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL);
         } catch (XMLConfigurationException e) {
             fGrammarPool = null;
         }
+
         // security features
         try {
             if (componentManager.getFeature(DISALLOW_DOCTYPE, false)) {
                 fSchemaParser.setFeature(DISALLOW_DOCTYPE, true);
             }
-        } catch (XMLConfigurationException e) {
-        }
+        } catch (XMLConfigurationException e) {}
+
         try {
-            Object security = componentManager.getProperty(SECURITY_MANAGER, null);
-            if (security != null){
-                fSchemaParser.setProperty(SECURITY_MANAGER, security);
+            if (fSecurityManager != null) {
+                fSchemaParser.setProperty(SECURITY_MANAGER, fSecurityManager);
             }
-        } catch (XMLConfigurationException e) {
-        }
-
-        XMLSecurityPropertyManager securityPropertyMgr = (XMLSecurityPropertyManager)
-                componentManager.getProperty(XML_SECURITY_PROPERTY_MANAGER);
+        } catch (XMLConfigurationException e) {}
+
+        fSecurityPropertyMgr = (XMLSecurityPropertyManager) componentManager.getProperty(XML_SECURITY_PROPERTY_MANAGER);
+
         //Passing on the setting to the parser
-        fSchemaParser.setProperty(XML_SECURITY_PROPERTY_MANAGER, securityPropertyMgr);
-
-        fAccessExternalDTD = securityPropertyMgr.getValue(
-                XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD);
-
-        fAccessExternalSchema = securityPropertyMgr.getValue(
-                XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA);
+        fSchemaParser.setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
+
+        fAccessExternalDTD = fSecurityPropertyMgr.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD);
+        fAccessExternalSchema = fSecurityPropertyMgr.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA);
 
     } // reset(XMLComponentManager)
 
@@ -4051,7 +4049,7 @@
          so long as there's some include/import/redefine path amongst them.
          If they rver reverse this decision the code's right here though...  - neilg
          // now look in fDependencyMap to see if this is reachable
-          if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) {
+          if((fDependencyMap.get(currSchema)).contains(declDocInfo)) {
           return declDocInfo;
           }
           // obviously the requesting doc didn't include, redefine or
@@ -4072,9 +4070,9 @@
         if (DOMUtil.isHidden(startSchema.fSchemaElement, fHiddenNodes)) {
             // make it visible
             DOMUtil.setVisible(startSchema.fSchemaElement, fHiddenNodes);
-            Vector dependingSchemas = (Vector)fDependencyMap.get(startSchema);
+            Vector<XSDocumentInfo> dependingSchemas = fDependencyMap.get(startSchema);
             for (int i = 0; i < dependingSchemas.size(); i++) {
-                setSchemasVisible((XSDocumentInfo)dependingSchemas.elementAt(i));
+                setSchemasVisible(dependingSchemas.elementAt(i));
             }
         }
         // if it's visible already than so must be its children
@@ -4107,7 +4105,7 @@
             ElementImpl ele = (ElementImpl)e;
             // get system id from document object
             Document doc = ele.getOwnerDocument();
-            String sid = (String)fDoc2SystemId.get(DOMUtil.getRoot(doc));
+            String sid = fDoc2SystemId.get(DOMUtil.getRoot(doc));
             // line/column numbers are stored in the element node
             int line = ele.getLineNumber();
             int column = ele.getColumnNumber();
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/XML11Configuration.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/XML11Configuration.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -52,7 +52,6 @@
 import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings;
 import com.sun.org.apache.xerces.internal.util.PropertyState;
 import com.sun.org.apache.xerces.internal.util.SymbolTable;
-import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
@@ -166,59 +165,57 @@
     protected static final String USE_GRAMMAR_POOL_ONLY =
         Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
 
-        // feature identifiers
+    // feature identifiers
 
-        /** Feature identifier: validation. */
-        protected static final String VALIDATION =
-                Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
+    /** Feature identifier: validation. */
+    protected static final String VALIDATION =
+        Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
 
-        /** Feature identifier: namespaces. */
-        protected static final String NAMESPACES =
-                Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
+    /** Feature identifier: namespaces. */
+    protected static final String NAMESPACES =
+        Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
 
-        /** Feature identifier: external general entities. */
-        protected static final String EXTERNAL_GENERAL_ENTITIES =
-                Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE;
+    /** Feature identifier: external general entities. */
+    protected static final String EXTERNAL_GENERAL_ENTITIES =
+        Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE;
 
-        /** Feature identifier: external parameter entities. */
-        protected static final String EXTERNAL_PARAMETER_ENTITIES =
-                Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE;
+    /** Feature identifier: external parameter entities. */
+    protected static final String EXTERNAL_PARAMETER_ENTITIES =
+        Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE;
 
-        /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */
-        protected static final String IGNORE_XSI_TYPE =
-            Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE;
+    /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */
+    protected static final String IGNORE_XSI_TYPE =
+        Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE;
 
-        /** Feature identifier: whether to ignore ID/IDREF errors */
-        protected static final String ID_IDREF_CHECKING =
-            Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE;
+    /** Feature identifier: whether to ignore ID/IDREF errors */
+    protected static final String ID_IDREF_CHECKING =
+        Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE;
 
-        /** Feature identifier: whether to ignore unparsed entity errors */
-        protected static final String UNPARSED_ENTITY_CHECKING =
-            Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE;
+    /** Feature identifier: whether to ignore unparsed entity errors */
+    protected static final String UNPARSED_ENTITY_CHECKING =
+        Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE;
 
-        /** Feature identifier: whether to ignore identity constraint errors */
-        protected static final String IDENTITY_CONSTRAINT_CHECKING =
-            Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE;
+    /** Feature identifier: whether to ignore identity constraint errors */
+    protected static final String IDENTITY_CONSTRAINT_CHECKING =
+        Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE;
 
     // property identifiers
 
+    /** Property identifier: xml string. */
+    protected static final String XML_STRING =
+        Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY;
 
-        /** Property identifier: xml string. */
-        protected static final String XML_STRING =
-                Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY;
-
-        /** Property identifier: symbol table. */
-        protected static final String SYMBOL_TABLE =
-                Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
+    /** Property identifier: symbol table. */
+    protected static final String SYMBOL_TABLE =
+        Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 
-        /** Property identifier: error handler. */
-        protected static final String ERROR_HANDLER =
-                Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
+    /** Property identifier: error handler. */
+    protected static final String ERROR_HANDLER =
+        Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
 
-        /** Property identifier: entity resolver. */
-        protected static final String ENTITY_RESOLVER =
-                Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
-
+    /** Property identifier: entity resolver. */
+    protected static final String ENTITY_RESOLVER =
+        Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
 
     /** Property identifier: XML Schema validator. */
     protected static final String SCHEMA_VALIDATOR =
@@ -232,8 +229,6 @@
     protected static final String SCHEMA_NONS_LOCATION =
         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION;
 
-    // property identifiers
-
     /** Property identifier: error reporter. */
     protected static final String ERROR_REPORTER =
         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
@@ -313,33 +308,33 @@
     // Data
     //
 
-        protected SymbolTable fSymbolTable;
+    protected SymbolTable fSymbolTable;
     protected XMLInputSource fInputSource;
     protected ValidationManager fValidationManager;
-        protected XMLVersionDetector fVersionDetector;
+    protected XMLVersionDetector fVersionDetector;
     protected XMLLocator fLocator;
-        protected Locale fLocale;
+    protected Locale fLocale;
 
-        /** XML 1.0 Components. */
-        protected ArrayList fComponents;
+    /** XML 1.0 Components. */
+    protected ArrayList<XMLComponent> fComponents;
 
-        /** XML 1.1. Components. */
-        protected ArrayList fXML11Components = null;
+    /** XML 1.1. Components. */
+    protected ArrayList<XMLComponent> fXML11Components = null;
 
-        /** Common components: XMLEntityManager, XMLErrorReporter, XMLSchemaValidator */
-        protected ArrayList fCommonComponents = null;
+    /** Common components: XMLEntityManager, XMLErrorReporter, XMLSchemaValidator */
+    protected ArrayList<XMLComponent> fCommonComponents = null;
 
-        /** The document handler. */
-        protected XMLDocumentHandler fDocumentHandler;
+    /** The document handler. */
+    protected XMLDocumentHandler fDocumentHandler;
 
-        /** The DTD handler. */
-        protected XMLDTDHandler fDTDHandler;
+    /** The DTD handler. */
+    protected XMLDTDHandler fDTDHandler;
 
-        /** The DTD content model handler. */
-        protected XMLDTDContentModelHandler fDTDContentModelHandler;
+    /** The DTD content model handler. */
+    protected XMLDTDContentModelHandler fDTDContentModelHandler;
 
-        /** Last component in the document pipeline */
-        protected XMLDocumentSource fLastComponent;
+    /** Last component in the document pipeline */
+    protected XMLDocumentSource fLastComponent;
 
     /**
      * True if a parse is in progress. This state is needed because
@@ -477,15 +472,15 @@
 
         // create a vector to hold all the components in use
         // XML 1.0 specialized components
-        fComponents = new ArrayList();
+        fComponents = new ArrayList<>();
         // XML 1.1 specialized components
-        fXML11Components = new ArrayList();
+        fXML11Components = new ArrayList<>();
         // Common components for XML 1.1. and XML 1.0
-        fCommonComponents = new ArrayList();
+        fCommonComponents = new ArrayList<>();
 
         // create table for features and properties
-        fFeatures = new HashMap();
-        fProperties = new HashMap();
+        fFeatures = new HashMap<>();
+        fProperties = new HashMap<>();
 
         // add default recognized features
         final String[] recognizedFeatures =
@@ -580,35 +575,35 @@
         }
 
         fEntityManager = new XMLEntityManager();
-                fProperties.put(ENTITY_MANAGER, fEntityManager);
+        fProperties.put(ENTITY_MANAGER, fEntityManager);
         addCommonComponent(fEntityManager);
 
         fErrorReporter = new XMLErrorReporter();
         fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner());
-                fProperties.put(ERROR_REPORTER, fErrorReporter);
+        fProperties.put(ERROR_REPORTER, fErrorReporter);
         addCommonComponent(fErrorReporter);
 
         fNamespaceScanner = new XMLNSDocumentScannerImpl();
-                fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner);
+        fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner);
         addComponent((XMLComponent) fNamespaceScanner);
 
         fDTDScanner = new XMLDTDScannerImpl();
-                fProperties.put(DTD_SCANNER, fDTDScanner);
+        fProperties.put(DTD_SCANNER, fDTDScanner);
         addComponent((XMLComponent) fDTDScanner);
 
         fDTDProcessor = new XMLDTDProcessor();
-                fProperties.put(DTD_PROCESSOR, fDTDProcessor);
+        fProperties.put(DTD_PROCESSOR, fDTDProcessor);
         addComponent((XMLComponent) fDTDProcessor);
 
         fDTDValidator = new XMLNSDTDValidator();
-                fProperties.put(DTD_VALIDATOR, fDTDValidator);
+        fProperties.put(DTD_VALIDATOR, fDTDValidator);
         addComponent(fDTDValidator);
 
         fDatatypeValidatorFactory = DTDDVFactory.getInstance();
-                fProperties.put(DATATYPE_VALIDATOR_FACTORY, fDatatypeValidatorFactory);
+        fProperties.put(DATATYPE_VALIDATOR_FACTORY, fDatatypeValidatorFactory);
 
         fValidationManager = new ValidationManager();
-                fProperties.put(VALIDATION_MANAGER, fValidationManager);
+        fProperties.put(VALIDATION_MANAGER, fValidationManager);
 
         fVersionDetector = new XMLVersionDetector();
 
@@ -935,20 +930,20 @@
                 // forward to every XML 1.0 component
                 int count = fComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fComponents.get(i);
+                        XMLComponent c = fComponents.get(i);
                         c.setFeature(featureId, state);
                 }
                 // forward it to common components
                 count = fCommonComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fCommonComponents.get(i);
+                        XMLComponent c = fCommonComponents.get(i);
                         c.setFeature(featureId, state);
                 }
 
                 // forward to every XML 1.1 component
                 count = fXML11Components.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fXML11Components.get(i);
+                        XMLComponent c = fXML11Components.get(i);
                         try{
                                 c.setFeature(featureId, state);
                         }
@@ -996,19 +991,19 @@
                 // forward to every XML 1.0 component
                 int count = fComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fComponents.get(i);
+                        XMLComponent c = fComponents.get(i);
                         c.setProperty(propertyId, value);
                 }
                 // forward it to every common Component
                 count = fCommonComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fCommonComponents.get(i);
+                        XMLComponent c = fCommonComponents.get(i);
                         c.setProperty(propertyId, value);
                 }
                 // forward it to every XML 1.1 component
                 count = fXML11Components.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fXML11Components.get(i);
+                        XMLComponent c = fXML11Components.get(i);
                         try{
                                 c.setProperty(propertyId, value);
                         }
@@ -1034,7 +1029,7 @@
         protected void reset() throws XNIException {
                 int count = fComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fComponents.get(i);
+                        XMLComponent c = fComponents.get(i);
                         c.reset(this);
                 }
 
@@ -1047,7 +1042,7 @@
                 // reset common components
                 int count = fCommonComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fCommonComponents.get(i);
+                        XMLComponent c = fCommonComponents.get(i);
                         c.reset(this);
                 }
 
@@ -1061,7 +1056,7 @@
                 // reset every component
                 int count = fXML11Components.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fXML11Components.get(i);
+                        XMLComponent c = fXML11Components.get(i);
                         c.reset(this);
                 }
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/HTTPInputSource.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/HTTPInputSource.java	Wed Jul 05 21:24:14 2017 +0200
@@ -51,7 +51,7 @@
     protected boolean fFollowRedirects = true;
 
     /** HTTP request properties. **/
-    protected Map fHTTPRequestProperties = new HashMap();
+    protected Map<String, String> fHTTPRequestProperties = new HashMap<>();
 
     //
     // Constructors
@@ -159,7 +159,7 @@
      * been set
      */
     public String getHTTPRequestProperty(String key) {
-        return (String) fHTTPRequestProperties.get(key);
+        return fHTTPRequestProperties.get(key);
     } // getHTTPRequestProperty(String):String
 
     /**
@@ -172,7 +172,7 @@
      * @return an iterator for the request properties this
      * input source contains
      */
-    public Iterator getHTTPRequestProperties() {
+    public Iterator<Map.Entry<String, String>> getHTTPRequestProperties() {
         return fHTTPRequestProperties.entrySet().iterator();
     } // getHTTPRequestProperties():Iterator
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/validation/Bug8149915.xsd	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+<xs:annotation>
+   <xs:appinfo>Testapp for XSD annotation issue</xs:appinfo>
+   <xs:documentation xml:lang="en">This is an XSD annotation, just for the sake of it.</xs:documentation>
+</xs:annotation>
+</xs:schema>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/validation/SchemaTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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 validation;
+
+import java.io.File;
+
+import javax.xml.XMLConstants;
+import javax.xml.validation.SchemaFactory;
+
+import org.testng.annotations.Test;
+
+/*
+ * @summary Test Schema creation
+ * @bug 8149915
+ */
+public class SchemaTest {
+
+    /*
+     * @bug 8149915
+     * Verifies that the annotation validator is initialized with the security manager for schema
+     * creation with http://apache.org/xml/features/validate-annotations=true.
+     */
+    @Test
+    public void testValidation() throws Exception {
+        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        factory.setFeature("http://apache.org/xml/features/validate-annotations", true);
+        factory.newSchema(new File(getClass().getResource("Bug8149915.xsd").getFile()));
+    }
+}
--- a/jaxws/.hgtags	Wed Jul 05 21:22:48 2017 +0200
+++ b/jaxws/.hgtags	Wed Jul 05 21:24:14 2017 +0200
@@ -352,3 +352,4 @@
 0f557aa096e2a5c9733d406d8cf0c2e6b1f8ca60 jdk-9+104
 45a666c58e4c7d07638878684ad09decb3229dc9 jdk-9+105
 c072c572d14948563ef5d86e1921699b3a2396ab jdk-9+106
+fafd694e801f0f5a7c737fb08630ced3ca8f772c jdk-9+107
--- a/jdk/.hgtags	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/.hgtags	Wed Jul 05 21:24:14 2017 +0200
@@ -349,3 +349,4 @@
 8faf1aec77a9517c69d2f4d8dd146429852ace7f jdk-9+104
 55518739e399a1066c8613e19100d51b38d9f223 jdk-9+105
 6e9ecae50b4e0d37483fb2719202eea5dca026a4 jdk-9+106
+8701b2bb1d2e1b9abc2a9be0933993c7150a9dbe jdk-9+107
--- a/jdk/make/gensrc/GensrcMisc.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/gensrc/GensrcMisc.gmk	Wed Jul 05 21:24:14 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
@@ -53,6 +53,8 @@
 $(eval $(call SetupNativeCompilation, BUILD_GENSRC_SOR_EXE, \
     SRC := $(GENSRC_SOR_SRC), \
     INCLUDE_FILES := $(GENSRC_SOR_SRC_FILE), \
+    CFLAGS_windows := -nologo, \
+    LDFLAGS_windows := -nologo, \
     TOOLCHAIN := TOOLCHAIN_BUILD, \
     OBJECT_DIR := $(GENSRC_SOR_BIN), \
     OUTPUT_DIR := $(GENSRC_SOR_BIN), \
@@ -61,12 +63,12 @@
 SOR_PREGEN_FILE := $(JDK_TOPDIR)/src/closed/java.base/$(OPENJDK_TARGET_OS)/classes/sun/nio/ch/SocketOptionRegistry-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH).java.template
 
 ifeq ($(wildcard $(SOR_PREGEN_FILE)), )
-  $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/ch/SocketOptionRegistry.java: $(BUILD_GENSRC_SOR_EXE)
+  $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/ch/SocketOptionRegistry.java: $(BUILD_GENSRC_SOR_EXE_TARGET)
 	$(MKDIR) -p $(@D)
 	$(RM) $@ $@.tmp
 	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e \
 	    $(JDK_TOPDIR)/make/scripts/addNotices.sh "$(SOR_COPYRIGHT_YEARS)" > $@.tmp
-	$(BUILD_GENSRC_SOR_EXE) >> $@.tmp
+	$(BUILD_GENSRC_SOR_EXE_TARGET) >> $@.tmp
 	$(MV) $@.tmp $@
 else
   $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/ch/SocketOptionRegistry.java: $(SOR_PREGEN_FILE)
@@ -97,12 +99,12 @@
   UC_PREGEN_FILE := $(JDK_TOPDIR)/src/closed/java.base/$(OPENJDK_TARGET_OS)/classes/sun/nio/fs/UnixConstants-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH).java.template
 
   ifeq ($(wildcard $(UC_PREGEN_FILE)), )
-    $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/UnixConstants.java: $(BUILD_GENSRC_UC_EXE)
+    $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/UnixConstants.java: $(BUILD_GENSRC_UC_EXE_TARGET)
 	$(MKDIR) -p $(@D)
 	$(RM) $@ $@.tmp
 	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e \
 	    $(JDK_TOPDIR)/make/scripts/addNotices.sh "$(UC_COPYRIGHT_YEARS)" > $@.tmp
-	$(BUILD_GENSRC_UC_EXE) >> $@.tmp
+	$(BUILD_GENSRC_UC_EXE_TARGET) >> $@.tmp
 	$(MV) $@.tmp $@
   else
     $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/UnixConstants.java: $(UC_PREGEN_FILE)
@@ -132,12 +134,12 @@
       OUTPUT_DIR := $(GENSRC_SOL_BIN), \
       PROGRAM := genSolarisConstants))
 
-  $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/SolarisConstants.java: $(BUILD_GENSRC_SOL_EXE)
+  $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/SolarisConstants.java: $(BUILD_GENSRC_SOL_EXE_TARGET)
 	$(MKDIR) -p $(@D)
 	$(RM) $@ $@.tmp
 	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e \
 	    $(JDK_TOPDIR)/make/scripts/addNotices.sh "$(SOL_COPYRIGHT_YEARS)" > $@.tmp
-	$(BUILD_GENSRC_SOL_EXE) >> $@.tmp
+	$(BUILD_GENSRC_SOL_EXE_TARGET) >> $@.tmp
 	$(MV) $@.tmp $@
 
 
--- a/jdk/make/lib/Awt2dLibraries.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/lib/Awt2dLibraries.gmk	Wed Jul 05 21:24:14 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
@@ -593,8 +593,8 @@
         LDFLAGS_solaris := $(call SET_SHARED_LIBRARY_ORIGIN,/..), \
         REORDER := $(LIBAWT_HEADLESS_REORDER), \
         LIBS_unix := -lawt -ljvm -ljava, \
-        LIBS_linux := -lm $(LIBDL), \
-        LIBS_solaris := -lm $(LIBDL) $(LIBCXX) -lc, \
+        LIBS_linux := $(LIBM) $(LIBDL), \
+        LIBS_solaris := $(LIBM) $(LIBDL) $(LIBCXX) -lc, \
         OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libawt_headless, \
     ))
 
--- a/jdk/make/lib/CoreLibraries.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/lib/CoreLibraries.gmk	Wed Jul 05 21:24:14 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
@@ -137,12 +137,6 @@
   endif
 endif
 
-ifeq ($(OPENJDK_TARGET_OS), linux)
-  ifeq ($(OPENJDK_TARGET_CPU), x86_64)
-    BUILD_LIBJAVA_Bits.c_CFLAGS := $(C_O_FLAG_NORM)
-  endif
-endif
-
 $(eval $(call SetupNativeCompilation,BUILD_LIBJAVA, \
     LIBRARY := java, \
     OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
@@ -163,7 +157,7 @@
     LIBS_unix := -ljvm -lverify, \
     LIBS_linux := $(LIBDL) $(BUILD_LIBFDLIBM), \
     LIBS_solaris := -lsocket -lnsl -lscf $(LIBDL) $(BUILD_LIBFDLIBM) -lc, \
-    LIBS_aix := $(LIBDL) $(BUILD_LIBFDLIBM) -lm,\
+    LIBS_aix := $(LIBDL) $(BUILD_LIBFDLIBM) $(LIBM),\
     LIBS_macosx := -lfdlibm \
         -framework CoreFoundation \
         -framework Foundation \
--- a/jdk/make/lib/Lib-java.instrument.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/lib/Lib-java.instrument.gmk	Wed Jul 05 21:24:14 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
@@ -67,7 +67,6 @@
         -L$(call FindLibDirForModule, java.base)/jli, \
     LDFLAGS_macosx := -Wl$(COMMA)-all_load, \
     LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
-    LDFLAGS_windows := -export:Agent_OnAttach, \
     LIBS := $(JDKLIB_LIBS), \
     LIBS_unix := -ljava $(LIBZ), \
     LIBS_linux := -ljli $(LIBDL), \
--- a/jdk/make/lib/Lib-jdk.jdi.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/lib/Lib-jdk.jdi.gmk	Wed Jul 05 21:24:14 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
--- a/jdk/make/lib/Lib-jdk.jdwp.agent.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/lib/Lib-jdk.jdwp.agent.gmk	Wed Jul 05 21:24:14 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
--- a/jdk/make/mapfiles/libjava/mapfile-vers	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/mapfiles/libjava/mapfile-vers	Wed Jul 05 21:24:14 2017 +0200
@@ -229,12 +229,6 @@
 		Java_java_lang_Throwable_fillInStackTrace;
                 Java_java_lang_Throwable_getStackTraceDepth;
                 Java_java_lang_Throwable_getStackTraceElement;
-                Java_java_nio_Bits_copyFromShortArray;
-                Java_java_nio_Bits_copyToShortArray;
-                Java_java_nio_Bits_copyFromIntArray;
-                Java_java_nio_Bits_copyToIntArray;
-                Java_java_nio_Bits_copyFromLongArray;
-                Java_java_nio_Bits_copyToLongArray;
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2;
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2;
--- a/jdk/make/mapfiles/libnet/mapfile-vers	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/mapfiles/libnet/mapfile-vers	Wed Jul 05 21:24:14 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
@@ -87,6 +87,9 @@
 		Java_java_net_PlainSocketImpl_socketConnect;
 		Java_java_net_PlainDatagramSocketImpl_getTimeToLive;
 		Java_java_net_PlainDatagramSocketImpl_setTimeToLive;
+                Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0;
+                Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0;
+                Java_jdk_net_Sockets_isReusePortAvailable0;
 		Java_sun_net_PortConfig_getUpper0;
 		Java_sun_net_PortConfig_getLower0;
 		Java_sun_net_dns_ResolverConfigurationImpl_localDomain0;
@@ -112,6 +115,7 @@
 		NET_EnableFastTcpLoopback;
 		NET_ThrowNew;
                 ipv6_available;
+                reuseport_available;
                 initInetAddressIDs;
 
 	local:
--- a/jdk/make/mapfiles/libnio/mapfile-linux	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/mapfiles/libnio/mapfile-linux	Wed Jul 05 21:24:14 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
@@ -109,6 +109,7 @@
 		Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
 		Java_sun_nio_ch_Net_isIPv6Available0;
+                Java_sun_nio_ch_Net_isReusePortAvailable0;
 		Java_sun_nio_ch_Net_joinOrDrop4;
 		Java_sun_nio_ch_Net_blockOrUnblock4;
 		Java_sun_nio_ch_Net_joinOrDrop6;
--- a/jdk/make/mapfiles/libnio/mapfile-macosx	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/mapfiles/libnio/mapfile-macosx	Wed Jul 05 21:24:14 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
@@ -102,6 +102,7 @@
 		Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
 		Java_sun_nio_ch_Net_isIPv6Available0;
+                Java_sun_nio_ch_Net_isReusePortAvailable0;
 		Java_sun_nio_ch_Net_joinOrDrop4;
 		Java_sun_nio_ch_Net_blockOrUnblock4;
 		Java_sun_nio_ch_Net_joinOrDrop6;
--- a/jdk/make/mapfiles/libnio/mapfile-solaris	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/mapfiles/libnio/mapfile-solaris	Wed Jul 05 21:24:14 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
@@ -97,6 +97,7 @@
 		Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
 		Java_sun_nio_ch_Net_isIPv6Available0;
+                Java_sun_nio_ch_Net_isReusePortAvailable0;
 		Java_sun_nio_ch_Net_joinOrDrop4;
 		Java_sun_nio_ch_Net_blockOrUnblock4;
 		Java_sun_nio_ch_Net_joinOrDrop6;
--- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java	Wed Jul 05 21:24:14 2017 +0200
@@ -248,10 +248,7 @@
             dir.mkdirs();
         }
         String className =
-            (CLDRConverter.isBaseModule ? "CLDRBaseLocaleDataMetaInfo" :
-                "CLDRLocaleDataMetaInfo_" +
-                CLDRConverter.DESTINATION_DIR.substring(CLDRConverter.DESTINATION_DIR.lastIndexOf('/')+1)
-                    .replaceAll("\\.", "_"));
+            (CLDRConverter.isBaseModule ? "CLDRBaseLocaleDataMetaInfo" : "CLDRLocaleDataMetaInfo");
         File file = new File(dir, className + ".java");
         if (!file.exists()) {
             file.createNewFile();
--- a/jdk/make/src/classes/build/tools/dtdbuilder/DTDParser.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/src/classes/build/tools/dtdbuilder/DTDParser.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, 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
@@ -908,16 +908,12 @@
             this.dtd = dtd;
             this.in = new DTDInputStream(in, dtd);
 
-            long tm = System.currentTimeMillis();
             ch = this.in.read();
             parseSection();
 
             if (ch != -1) {
                 error("premature");
             }
-
-            tm = System.currentTimeMillis() - tm;
-            System.err.println("[Parsed DTD " + dtd + " in " + tm + "ms]");
         } catch (IOException e) {
             error("ioexception");
         } catch (Exception e) {
--- a/jdk/make/src/classes/build/tools/module/boot.modules	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/src/classes/build/tools/module/boot.modules	Wed Jul 05 21:24:14 2017 +0200
@@ -2,6 +2,7 @@
 java.compiler
 java.datatransfer
 java.desktop
+java.httpclient
 java.instrument
 java.logging
 java.management
--- a/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, 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
@@ -34,6 +34,21 @@
 #include <netinet/tcp.h>
 #endif
 
+/* Defines SO_REUSEPORT */
+#if !defined(SO_REUSEPORT)
+#ifdef _WIN32
+#define SO_REUSEPORT 0
+#elif __linux__
+#define SO_REUSEPORT 15
+#elif __solaris__
+#define SO_REUSEPORT 0x100e
+#elif defined(AIX) || defined(MACOSX)
+#define SO_REUSEPORT 0x0200
+#else
+#define SO_REUSEPORT 0
+#endif
+#endif
+
 /**
  * Generates sun.nio.ch.SocketOptionRegistry, a class that maps Java-level
  * socket options to the platform specific level and option.
@@ -102,6 +117,7 @@
     emit_unspec("StandardSocketOptions.SO_SNDBUF",    SOL_SOCKET, SO_SNDBUF);
     emit_unspec("StandardSocketOptions.SO_RCVBUF",    SOL_SOCKET, SO_RCVBUF);
     emit_unspec("StandardSocketOptions.SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR);
+    emit_unspec("StandardSocketOptions.SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT);
     emit_unspec("StandardSocketOptions.TCP_NODELAY",  IPPROTO_TCP, TCP_NODELAY);
 
     emit_inet("StandardSocketOptions.IP_TOS",            IPPROTO_IP,     IP_TOS);
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, 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
@@ -1026,6 +1026,9 @@
   .asCollector(long[].class, 1);
 assertEquals("[123]", (String) longsToString.invokeExact((long)123));
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
      * @param arrayLength the number of arguments to collect into a new array argument
      * @return a new method handle which collects some trailing argument
@@ -1067,6 +1070,9 @@
     swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
     assertEquals("BCPQRSZ", swr.toString());
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param collectArgPos the zero-based position in the parameter list at which to start collecting.
      * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
      * @param arrayLength the number of arguments to collect into a new array argument
@@ -1356,8 +1362,11 @@
      * The reference {@code x} must be convertible to the first parameter
      * type of the target.
      * <p>
-     * (<em>Note:</em>  Because method handles are immutable, the target method handle
-     * retains its original type and behavior.)
+     * <em>Note:</em>  Because method handles are immutable, the target method handle
+     * retains its original type and behavior.
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param x  the value to bind to the first argument of the target
      * @return a new method handle which prepends the given value to the incoming
      *         argument list, before calling the original method handle
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -778,8 +778,21 @@
             return (asTypeCache = wrapper);
         }
 
+        // Customize target if counting happens for too long.
+        private int invocations = CUSTOMIZE_THRESHOLD;
+        private void maybeCustomizeTarget() {
+            int c = invocations;
+            if (c >= 0) {
+                if (c == 1) {
+                    target.customize();
+                }
+                invocations = c - 1;
+            }
+        }
+
         boolean countDown() {
             int c = count;
+            maybeCustomizeTarget();
             if (c <= 1) {
                 // Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
                 if (isCounting) {
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Jul 05 21:24:14 2017 +0200
@@ -2139,7 +2139,7 @@
      * if its index does not appear in the array.
      * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
      * incoming arguments which are not mentioned in the reordering array
-     * are may be any type, as determined only by {@code newType}.
+     * may be of any type, as determined only by {@code newType}.
      * <blockquote><pre>{@code
 import static java.lang.invoke.MethodHandles.*;
 import static java.lang.invoke.MethodType.*;
@@ -2157,6 +2157,9 @@
 assert(twice.type().equals(intfn1));
 assert((int)twice.invokeExact(21) == 42);
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param target the method handle to invoke after arguments are reordered
      * @param newType the expected type of the new method handle
      * @param reorder an index array which controls the reordering
@@ -2421,6 +2424,9 @@
      * It may range between zero and <i>N-L</i> (inclusively),
      * where <i>N</i> is the arity of the target method handle
      * and <i>L</i> is the length of the values array.
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param target the method handle to invoke after the argument is inserted
      * @param pos where to insert the argument (zero for the first)
      * @param values the series of arguments to insert
@@ -2639,14 +2645,25 @@
 MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
 assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * denotes the return type of both the {@code target} and resulting adapter.
+     * {@code P}/{@code p} and {@code B}/{@code b} represent the types and values
+     * of the parameters and arguments that precede and follow the filter position
+     * {@code pos}, respectively. {@code A[i]}/{@code a[i]} stand for the types and
+     * values of the filtered parameters and arguments; they also represent the
+     * return types of the {@code filter[i]} handles. The latter accept arguments
+     * {@code v[i]} of type {@code V[i]}, which also appear in the signature of
+     * the resulting adapter.
      * <blockquote><pre>{@code
-     * V target(P... p, A[i]... a[i], B... b);
+     * T target(P... p, A[i]... a[i], B... b);
      * A[i] filter[i](V[i]);
      * T adapter(P... p, V[i]... v[i], B... b) {
-     *   return target(p..., f[i](v[i])..., b...);
+     *   return target(p..., filter[i](v[i])..., b...);
      * }
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      *
      * @param target the method handle to invoke after arguments are filtered
      * @param pos the position of the first argument to filter
@@ -2753,7 +2770,17 @@
 assertEquals("[top, [[up, down, strange], charm], bottom]",
              (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the return type of the {@code target} and resulting adapter.
+     * {@code V}/{@code v} stand for the return type and value of the
+     * {@code filter}, which are also found in the signature and arguments of
+     * the {@code target}, respectively, unless {@code V} is {@code void}.
+     * {@code A}/{@code a} and {@code C}/{@code c} represent the parameter types
+     * and values preceding and following the collection position, {@code pos},
+     * in the {@code target}'s signature. They also turn up in the resulting
+     * adapter's signature and arguments, where they surround
+     * {@code B}/{@code b}, which represent the parameter types and arguments
+     * to the {@code filter} (if any).
      * <blockquote><pre>{@code
      * T target(A...,V,C...);
      * V filter(B...);
@@ -2771,7 +2798,7 @@
      * // and if the filter has a void return:
      * T target3(A...,C...);
      * void filter3(B...);
-     * void adapter3(A... a,B... b,C... c) {
+     * T adapter3(A... a,B... b,C... c) {
      *   filter3(b...);
      *   return target3(a...,c...);
      * }
@@ -2791,6 +2818,9 @@
      * a non-void result, then {@code collectArguments(mh, N, coll)}
      * is equivalent to {@code filterArguments(mh, N, coll)}.
      * Other equivalences are possible but would require argument permutation.
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      *
      * @param target the method handle to invoke after filtering the subsequence of arguments
      * @param pos the position of the first adapter argument to pass to the filter,
@@ -2864,29 +2894,36 @@
 MethodHandle f0 = filterReturnValue(cat, length);
 System.out.println((int) f0.invokeExact("x", "y")); // 2
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code,
+     * {@code T}/{@code t} represent the result type and value of the
+     * {@code target}; {@code V}, the result type of the {@code filter}; and
+     * {@code A}/{@code a}, the types and values of the parameters and arguments
+     * of the {@code target} as well as the resulting adapter.
      * <blockquote><pre>{@code
-     * V target(A...);
-     * T filter(V);
-     * T adapter(A... a) {
-     *   V v = target(a...);
-     *   return filter(v);
+     * T target(A...);
+     * V filter(T);
+     * V adapter(A... a) {
+     *   T t = target(a...);
+     *   return filter(t);
      * }
      * // and if the target has a void return:
      * void target2(A...);
-     * T filter2();
-     * T adapter2(A... a) {
+     * V filter2();
+     * V adapter2(A... a) {
      *   target2(a...);
      *   return filter2();
      * }
      * // and if the filter has a void return:
-     * V target3(A...);
+     * T target3(A...);
      * void filter3(V);
      * void adapter3(A... a) {
-     *   V v = target3(a...);
-     *   filter3(v);
+     *   T t = target3(a...);
+     *   filter3(t);
      * }
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param target the method handle to invoke before filtering the return value
      * @param filter method handle to call on the return value
      * @return method handle which incorporates the specified return value filtering logic
@@ -2964,7 +3001,15 @@
 // also prints "boo":
 assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the result type of the {@code target} and resulting adapter.
+     * {@code V}/{@code v} represent the type and value of the parameter and argument
+     * of {@code target} that precedes the folding position; {@code V} also is
+     * the result type of the {@code combiner}. {@code A}/{@code a} denote the
+     * types and values of the {@code N} parameters and arguments at the folding
+     * position. {@code B}/{@code b} represent the types and values of the
+     * {@code target} parameters and arguments that follow the folded parameters
+     * and arguments.
      * <blockquote><pre>{@code
      * // there are N arguments in A...
      * T target(V, A[N]..., B...);
@@ -2981,6 +3026,9 @@
      *   return target2(a..., b...);
      * }
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param target the method handle to invoke after arguments are combined
      * @param combiner method handle to call initially on the incoming arguments
      * @return method handle which incorporates the specified argument folding logic
@@ -3022,7 +3070,13 @@
      * argument and return types, except that the return type
      * of the test must be boolean, and the test is allowed
      * to have fewer arguments than the other two method handles.
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>
+     * Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the uniform result type of the three involved handles;
+     * {@code A}/{@code a}, the types and values of the {@code target}
+     * parameters and arguments that are consumed by the {@code test}; and
+     * {@code B}/{@code b}, those types and values of the {@code target}
+     * parameters and arguments that are not consumed by the {@code test}.
      * <blockquote><pre>{@code
      * boolean test(A...);
      * T target(A...,B...);
@@ -3084,7 +3138,13 @@
      * argument and return types, except that handler may omit trailing arguments
      * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
      * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>
+     * Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the return type of the {@code target} and {@code handler},
+     * and correspondingly that of the resulting adapter; {@code A}/{@code a},
+     * the types and values of arguments to the resulting handle consumed by
+     * {@code handler}; and {@code B}/{@code b}, those of arguments to the
+     * resulting handle discarded by {@code handler}.
      * <blockquote><pre>{@code
      * T target(A..., B...);
      * T handler(ExType, A...);
@@ -3828,8 +3888,9 @@
      * (Note that, except for argument type conversions, combinators represent {@code void} values in parameter lists
      * by omitting the corresponding paradoxical arguments, not by inserting {@code null} or zero values.)
      * <p>
-     * The {@code target} and {@code cleanup} handles' return types must be the same. Their parameter type lists also
-     * must be the same, but the {@code cleanup} handle must accept one or two more leading parameters:<ul>
+     * The {@code target} and {@code cleanup} handles must have the same corresponding argument and return types, except
+     * that the {@code cleanup} handle may omit trailing arguments. Also, the {@code cleanup} handle must have one or
+     * two extra leading parameters:<ul>
      * <li>a {@code Throwable}, which will carry the exception thrown by the {@code target} handle (if any); and
      * <li>a parameter of the same type as the return type of both {@code target} and {@code cleanup}, which will carry
      * the result from the execution of the {@code target} handle.
@@ -3932,7 +3993,16 @@
     // also prints "jum":
     assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the result type of the {@code target} and resulting adapter.
+     * {@code V}/{@code v} represent the type and value of the parameter and argument
+     * of {@code target} that precedes the folding position; {@code V} also is
+     * the result type of the {@code combiner}. {@code A}/{@code a} denote the
+     * types and values of the {@code N} parameters and arguments at the folding
+     * position. {@code Z}/{@code z} and {@code B}/{@code b} represent the types
+     * and values of the {@code target} parameters and arguments that precede and
+     * follow the folded parameters and arguments starting at {@code pos},
+     * respectively.
      * <blockquote><pre>{@code
      * // there are N arguments in A...
      * T target(Z..., V, A[N]..., B...);
@@ -3949,6 +4019,9 @@
      *   return target2(z..., a..., b...);
      * }
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      *
      * @param target the method handle to invoke after arguments are combined
      * @param pos the position at which to start folding and at which to insert the folding result; if this is {@code
@@ -4064,8 +4137,10 @@
         // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
         // target parameter list.
         int cleanupArgIndex = rtype == void.class ? 1 : 2;
-        if (!cleanupParamTypes.subList(cleanupArgIndex, cleanupParamTypes.size()).
-                equals(target.type().parameterList().subList(0, cleanupParamTypes.size() - cleanupArgIndex))) {
+        List<Class<?>> cleanupArgSuffix = cleanupParamTypes.subList(cleanupArgIndex, cleanupParamTypes.size());
+        List<Class<?>> targetParamTypes = target.type().parameterList();
+        if (targetParamTypes.size() < cleanupArgSuffix.size() ||
+                !cleanupArgSuffix.equals(targetParamTypes.subList(0, cleanupParamTypes.size() - cleanupArgIndex))) {
             throw misMatchedTypes("cleanup parameters after (Throwable,result) and target parameter list prefix",
                     cleanup.type(), target.type());
         }
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java	Wed Jul 05 21:24:14 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
@@ -28,6 +28,9 @@
 import java.io.IOException;
 import java.security.AccessController;
 import sun.net.ResourceManager;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
 
 /**
  * Abstract datagram and multicast socket implementation base class.
@@ -70,6 +73,45 @@
             });
     }
 
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
+
+    /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
+    private static volatile Set<SocketOption<?>> socketOptions;
+
+    /**
+     * Returns a set of SocketOptions supported by this impl
+     * and by this impl's socket (Socket or ServerSocket)
+     *
+     * @return a Set of SocketOptions
+     */
+    @Override
+    protected Set<SocketOption<?>> supportedOptions() {
+        Set<SocketOption<?>> options = socketOptions;
+        if (options == null) {
+            if (isReusePortAvailable()) {
+                options = new HashSet<>();
+                options.addAll(super.supportedOptions());
+                options.add(StandardSocketOptions.SO_REUSEPORT);
+                options = Collections.unmodifiableSet(options);
+            } else {
+                options = super.supportedOptions();
+            }
+            socketOptions = options;
+        }
+        return options;
+    }
+
     /**
      * Creates a datagram socket
      */
@@ -303,6 +345,14 @@
              if (o == null || !(o instanceof Boolean))
                  throw new SocketException("bad argument for IP_MULTICAST_LOOP");
              break;
+         case SO_REUSEPORT:
+             if (o == null || !(o instanceof Boolean)) {
+                 throw new SocketException("bad argument for SO_REUSEPORT");
+             }
+             if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+                 throw new UnsupportedOperationException("unsupported option");
+             }
+             break;
          default:
              throw new SocketException("invalid option: " + optID);
          }
@@ -343,6 +393,13 @@
                 result = socketGetOption(optID);
                 break;
 
+            case SO_REUSEPORT:
+                if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+                    throw new UnsupportedOperationException("unsupported option");
+                }
+                result = socketGetOption(optID);
+                break;
+
             default:
                 throw new SocketException("invalid option: " + optID);
         }
@@ -364,4 +421,5 @@
     }
 
     abstract int dataAvailable();
+    private static native boolean isReusePortAvailable0();
 }
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, 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
@@ -33,6 +33,9 @@
 import sun.net.ConnectionResetException;
 import sun.net.NetHooks;
 import sun.net.ResourceManager;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
 
 /**
  * Default Socket Implementation. This implementation does
@@ -87,6 +90,45 @@
             });
     }
 
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
+
+    /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
+    private static volatile Set<SocketOption<?>> socketOptions;
+
+   /**
+    * Returns a set of SocketOptions supported by this impl
+    * and by this impl's socket (Socket or ServerSocket)
+    *
+    * @return a Set of SocketOptions
+    */
+    @Override
+    protected Set<SocketOption<?>> supportedOptions() {
+        Set<SocketOption<?>> options = socketOptions;
+        if (options == null) {
+            if (isReusePortAvailable()) {
+                options = new HashSet<>();
+                options.addAll(super.supportedOptions());
+                options.add(StandardSocketOptions.SO_REUSEPORT);
+                options = Collections.unmodifiableSet(options);
+            } else {
+                options = super.supportedOptions();
+            }
+            socketOptions = options;
+        }
+        return options;
+    }
+
     /**
      * Creates a socket with a boolean that specifies whether this
      * is a stream socket (true) or an unconnected UDP socket (false).
@@ -269,6 +311,13 @@
                 throw new SocketException("bad parameter for SO_REUSEADDR");
             on = ((Boolean)val).booleanValue();
             break;
+        case SO_REUSEPORT:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_REUSEPORT");
+            if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT))
+                throw new UnsupportedOperationException("unsupported option");
+            on = ((Boolean)val).booleanValue();
+            break;
         default:
             throw new SocketException("unrecognized TCP option: " + opt);
         }
@@ -326,6 +375,12 @@
         case SO_KEEPALIVE:
             ret = socketGetOption(opt, null);
             return Boolean.valueOf(ret != -1);
+        case SO_REUSEPORT:
+            if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+                throw new UnsupportedOperationException("unsupported option");
+            }
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
         // should never get here
         default:
             return null;
@@ -723,4 +778,6 @@
 
     public static final int SHUT_RD = 0;
     public static final int SHUT_WR = 1;
+
+    private static native boolean isReusePortAvailable0();
 }
--- a/jdk/src/java.base/share/classes/java/net/Authenticator.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/Authenticator.java	Wed Jul 05 21:24:14 2017 +0200
@@ -320,6 +320,48 @@
     }
 
     /**
+     * Ask this authenticator for a password.
+     *
+     * @param host The hostname of the site requesting authentication.
+     * @param addr The InetAddress of the site requesting authorization,
+     *             or null if not known.
+     * @param port the port for the requested connection
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user
+     * @param scheme The authentication scheme
+     * @param url The requesting URL that caused the authentication
+     * @param reqType The type (server or proxy) of the entity requesting
+     *              authentication.
+     *
+     * @return The username/password, or null if one can't be gotten
+     *
+     * @since 9
+     */
+    public PasswordAuthentication
+    requestPasswordAuthenticationInstance(String host,
+                                          InetAddress addr,
+                                          int port,
+                                          String protocol,
+                                          String prompt,
+                                          String scheme,
+                                          URL url,
+                                          RequestorType reqType) {
+        synchronized (this) {
+            this.reset();
+            this.requestingHost = host;
+            this.requestingSite = addr;
+            this.requestingPort = port;
+            this.requestingProtocol = protocol;
+            this.requestingPrompt = prompt;
+            this.requestingScheme = scheme;
+            this.requestingURL = url;
+            this.requestingAuthType = reqType;
+            return this.getPasswordAuthentication();
+        }
+    }
+
+    /**
      * Gets the {@code hostname} of the
      * site or proxy requesting authentication, or {@code null}
      * if not available.
--- a/jdk/src/java.base/share/classes/java/net/DatagramSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/DatagramSocketImpl.java	Wed Jul 05 21:24:14 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
@@ -287,6 +287,9 @@
             setOption(SocketOptions.SO_RCVBUF, value);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
+            supportedOptions().contains(name)) {
+            setOption(SocketOptions.SO_REUSEPORT, value);
         } else if (name == StandardSocketOptions.IP_TOS) {
             setOption(SocketOptions.IP_TOS, value);
         } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
@@ -329,6 +332,9 @@
             return (T) getOption(SocketOptions.SO_RCVBUF);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             return (T) getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
+            supportedOptions().contains(name)) {
+            return (T) getOption(SocketOptions.SO_REUSEPORT);
         } else if (name == StandardSocketOptions.IP_TOS) {
             return (T) getOption(SocketOptions.IP_TOS);
         } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
--- a/jdk/src/java.base/share/classes/java/net/JarURLConnection.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/JarURLConnection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -173,6 +173,14 @@
         }
 
         jarFileURL = new URL(spec.substring(0, separator++));
+        /*
+         * The url argument may have had a runtime fragment appended, so
+         * we need to add a runtime fragment to the jarFileURL to enable
+         * runtime versioning when the underlying jar file is opened.
+         */
+        if ("runtime".equals(url.getRef())) {
+            jarFileURL = new URL(jarFileURL, "#runtime");
+        }
         entryName = null;
 
         /* if ! is the last letter of the innerURL, entryName is null */
--- a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2014, 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
@@ -98,7 +98,11 @@
      * <p>
      * When the socket is created the
      * {@link DatagramSocket#setReuseAddress(boolean)} method is
-     * called to enable the SO_REUSEADDR socket option.
+     * called to enable the SO_REUSEADDR socket option. When
+     * {@link StandardSocketOptions#SO_REUSEPORT SO_REUSEPORT} is
+     * supported then
+     * {@link DatagramSocketImpl#setOption(SocketOption, Object)}
+     * is called to enable the socket option.
      *
      * @exception IOException if an I/O exception occurs
      * while creating the MulticastSocket
@@ -106,6 +110,7 @@
      *             {@code checkListen} method doesn't allow the operation.
      * @see SecurityManager#checkListen
      * @see java.net.DatagramSocket#setReuseAddress(boolean)
+     * @see java.net.DatagramSocketImpl#setOption(SocketOption, Object)
      */
     public MulticastSocket() throws IOException {
         this(new InetSocketAddress(0));
@@ -167,6 +172,11 @@
         // Enable SO_REUSEADDR before binding
         setReuseAddress(true);
 
+        // Enable SO_REUSEPORT if supported before binding
+        if (supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+            this.setOption(StandardSocketOptions.SO_REUSEPORT, true);
+        }
+
         if (bindaddr != null) {
             try {
                 bind(bindaddr);
--- a/jdk/src/java.base/share/classes/java/net/ProxySelector.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/ProxySelector.java	Wed Jul 05 21:24:14 2017 +0200
@@ -162,4 +162,49 @@
      * @throws IllegalArgumentException if either argument is null
      */
     public abstract void connectFailed(URI uri, SocketAddress sa, IOException ioe);
+
+    /**
+     * Returns a ProxySelector which uses the given proxy address for all HTTP
+     * and HTTPS requests. If proxy is {@code null} then proxying is disabled.
+     *
+     * @param proxyAddress
+     *        The address of the proxy
+     *
+     * @return a ProxySelector
+     *
+     * @since 9
+     */
+    public static ProxySelector of(InetSocketAddress proxyAddress) {
+        return new StaticProxySelector(proxyAddress);
+    }
+
+    static class StaticProxySelector extends ProxySelector {
+        private static final List<Proxy> NO_PROXY_LIST = List.of(Proxy.NO_PROXY);
+        final List<Proxy> list;
+
+        StaticProxySelector(InetSocketAddress address){
+            Proxy p;
+            if (address == null) {
+                p = Proxy.NO_PROXY;
+            } else {
+                p = new Proxy(Proxy.Type.HTTP, address);
+            }
+            list = List.of(p);
+        }
+
+        @Override
+        public void connectFailed(URI uri, SocketAddress sa, IOException e) {
+            /* ignore */
+        }
+
+        @Override
+        public synchronized List<Proxy> select(URI uri) {
+            String scheme = uri.getScheme().toLowerCase();
+            if (scheme.equals("http") || scheme.equals("https")) {
+                return list;
+            } else {
+                return NO_PROXY_LIST;
+            }
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/java/net/SocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/SocketImpl.java	Wed Jul 05 21:24:14 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
@@ -386,6 +386,9 @@
             setOption(SocketOptions.SO_RCVBUF, value);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
+            supportedOptions().contains(name)) {
+            setOption(SocketOptions.SO_REUSEPORT, value);
         } else if (name == StandardSocketOptions.SO_LINGER &&
                 (getSocket() != null)) {
             setOption(SocketOptions.SO_LINGER, value);
@@ -426,6 +429,9 @@
             return (T)getOption(SocketOptions.SO_RCVBUF);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             return (T)getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
+            supportedOptions().contains(name)) {
+            return (T)getOption(SocketOptions.SO_REUSEPORT);
         } else if (name == StandardSocketOptions.SO_LINGER &&
                 (getSocket() != null)) {
             return (T)getOption(SocketOptions.SO_LINGER);
--- a/jdk/src/java.base/share/classes/java/net/SocketOptions.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/SocketOptions.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, 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
@@ -170,6 +170,17 @@
 
     @Native public static final int SO_REUSEADDR = 0x04;
 
+    /** Sets SO_REUSEPORT for a socket. This option enables and disables
+     *  the ability to have multiple sockets listen to the same address
+     *  and port.
+     * <P>
+     * Valid for: SocketImpl, DatagramSocketImpl
+     *
+     * @since 9
+     * @see StandardSocketOptions#SO_REUSEPORT
+     */
+    @Native public static final int SO_REUSEPORT = 0x0E;
+
     /**
      * Sets SO_BROADCAST for a socket. This option enables and disables
      * the ability of the process to send broadcast messages. It is supported
--- a/jdk/src/java.base/share/classes/java/net/StandardSocketOptions.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/StandardSocketOptions.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -187,6 +187,29 @@
         new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class);
 
     /**
+     * Re-use port.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The exact semantics of this
+     * socket option are socket type and system dependent.
+     *
+     * <p> In the case of stream-oriented sockets, this socket option usually allows
+     * multiple listening sockets to be bound to both same address
+     * and same port.
+     *
+     * <p> For datagram-oriented sockets the socket option usually allows
+     * multiple UDP sockets to be bound to the same address and port.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Changing the value of this socket option
+     * after the socket is bound has no effect.
+     *
+     * @since 9
+     */
+    public static final SocketOption<Boolean> SO_REUSEPORT =
+        new StdSocketOption<Boolean>("SO_REUSEPORT", Boolean.class);
+
+    /**
      * Linger on close if data is present.
      *
      * <p> The value of this socket option is an {@code Integer} that controls
--- a/jdk/src/java.base/share/classes/java/net/package-info.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/package-info.java	Wed Jul 05 21:24:14 2017 +0200
@@ -121,7 +121,8 @@
  *            underlying protocol handlers like http or https.</li>
  *       <li>{@link java.net.HttpURLConnection} is a subclass of URLConnection
  *            and provides some additional functionalities specific to the
- *            HTTP protocol.</li>
+ *            HTTP protocol. This API has been superceded by the newer
+              HTTP client API described in the previous section.</li>
  * </ul>
  * <p>The recommended usage is to use {@link java.net.URI} to identify
  *    resources, then convert it into a {@link java.net.URL} when it is time to
--- a/jdk/src/java.base/share/classes/java/nio/Bits.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/nio/Bits.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -807,31 +807,131 @@
         }
     }
 
-    static void copyFromCharArray(Object src, long srcPos, long dstAddr,
-                                  long length)
-    {
-        copyFromShortArray(src, srcPos, dstAddr, length);
+    /**
+     * Copy and unconditionally byte swap 16 bit elements from a heap array to off-heap memory
+     *
+     * @param src
+     *        the source array, must be a 16-bit primitive array type
+     * @param srcPos
+     *        byte offset within source array of the first element to read
+     * @param dstAddr
+     *        destination address
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyFromCharArray(Object src, long srcPos, long dstAddr, long length) {
+        unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 2);
     }
 
-    static void copyToCharArray(long srcAddr, Object dst, long dstPos,
-                                long length)
-    {
-        copyToShortArray(srcAddr, dst, dstPos, length);
+    /**
+     * Copy and unconditionally byte swap 16 bit elements from off-heap memory to a heap array
+     *
+     * @param srcAddr
+     *        source address
+     * @param dst
+     *        destination array, must be a 16-bit primitive array type
+     * @param dstPos
+     *        byte offset within the destination array of the first element to write
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyToCharArray(long srcAddr, Object dst, long dstPos, long length) {
+        unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 2);
+    }
+
+    /**
+     * Copy and unconditionally byte swap 16 bit elements from a heap array to off-heap memory
+     *
+     * @param src
+     *        the source array, must be a 16-bit primitive array type
+     * @param srcPos
+     *        byte offset within source array of the first element to read
+     * @param dstAddr
+     *        destination address
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyFromShortArray(Object src, long srcPos, long dstAddr, long length) {
+        unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 2);
+    }
+
+    /**
+     * Copy and unconditionally byte swap 16 bit elements from off-heap memory to a heap array
+     *
+     * @param srcAddr
+     *        source address
+     * @param dst
+     *        destination array, must be a 16-bit primitive array type
+     * @param dstPos
+     *        byte offset within the destination array of the first element to write
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyToShortArray(long srcAddr, Object dst, long dstPos, long length) {
+        unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 2);
     }
 
-    static native void copyFromShortArray(Object src, long srcPos, long dstAddr,
-                                          long length);
-    static native void copyToShortArray(long srcAddr, Object dst, long dstPos,
-                                        long length);
+    /**
+     * Copy and unconditionally byte swap 32 bit elements from a heap array to off-heap memory
+     *
+     * @param src
+     *        the source array, must be a 32-bit primitive array type
+     * @param srcPos
+     *        byte offset within source array of the first element to read
+     * @param dstAddr
+     *        destination address
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyFromIntArray(Object src, long srcPos, long dstAddr, long length) {
+        unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 4);
+    }
+
+    /**
+     * Copy and unconditionally byte swap 32 bit elements from off-heap memory to a heap array
+     *
+     * @param srcAddr
+     *        source address
+     * @param dst
+     *        destination array, must be a 32-bit primitive array type
+     * @param dstPos
+     *        byte offset within the destination array of the first element to write
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyToIntArray(long srcAddr, Object dst, long dstPos, long length) {
+        unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 4);
+    }
 
-    static native void copyFromIntArray(Object src, long srcPos, long dstAddr,
-                                        long length);
-    static native void copyToIntArray(long srcAddr, Object dst, long dstPos,
-                                      long length);
+    /**
+     * Copy and unconditionally byte swap 64 bit elements from a heap array to off-heap memory
+     *
+     * @param src
+     *        the source array, must be a 64-bit primitive array type
+     * @param srcPos
+     *        byte offset within source array of the first element to read
+     * @param dstAddr
+     *        destination address
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyFromLongArray(Object src, long srcPos, long dstAddr, long length) {
+        unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 8);
+    }
 
-    static native void copyFromLongArray(Object src, long srcPos, long dstAddr,
-                                         long length);
-    static native void copyToLongArray(long srcAddr, Object dst, long dstPos,
-                                       long length);
-
+    /**
+     * Copy and unconditionally byte swap 64 bit elements from off-heap memory to a heap array
+     *
+     * @param srcAddr
+     *        source address
+     * @param dst
+     *        destination array, must be a 64-bit primitive array type
+     * @param dstPos
+     *        byte offset within the destination array of the first element to write
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyToLongArray(long srcAddr, Object dst, long dstPos, long length) {
+        unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 8);
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/Currency.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/Currency.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -92,7 +92,12 @@
  * and the remainder of entries in file are processed. For instances where duplicate
  * country code entries exist, the behavior of the Currency information for that
  * {@code Currency} is undefined and the remainder of entries in file are processed.
+ * <p>
+ * It is recommended to use {@link java.math.BigDecimal} class while dealing
+ * with {@code Currency} or monetary values as it provides better handling of floating
+ * point numbers and their operations.
  *
+ * @see java.math.BigDecimal
  * @since 1.4
  */
 public final class Currency implements Serializable {
@@ -516,14 +521,16 @@
     }
 
     /**
-     * Gets the default number of fraction digits used with this currency.
-     * For example, the default number of fraction digits for the Euro is 2,
-     * while for the Japanese Yen it's 0.
-     * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
-     * -1 is returned.
-     *
-     * @return the default number of fraction digits used with this currency
-     */
+    * Gets the default number of fraction digits used with this currency.
+    * Note that the number of fraction digits is the same as ISO 4217's
+    * minor unit for the currency.
+    * For example, the default number of fraction digits for the Euro is 2,
+    * while for the Japanese Yen it's 0.
+    * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
+    * -1 is returned.
+    *
+    * @return the default number of fraction digits used with this currency
+    */
     public int getDefaultFractionDigits() {
         return defaultFractionDigits;
     }
--- a/jdk/src/java.base/share/classes/java/util/jar/Attributes.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/jar/Attributes.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -646,5 +646,13 @@
          * manifest attribute used for package versioning.
          */
         public static final Name SPECIFICATION_VENDOR = new Name("Specification-Vendor");
+
+        /**
+         * {@code Name} object for {@code Multi-Release}
+         * manifest attribute that indicates this is a multi-release JAR file.
+         *
+         * @since   9
+         */
+        public static final Name MULTI_RELEASE = new Name("Multi-Release");
     }
 }
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Wed Jul 05 21:24:14 2017 +0200
@@ -28,6 +28,7 @@
 import java.io.*;
 import java.lang.ref.SoftReference;
 import java.net.URL;
+import java.security.PrivilegedAction;
 import java.util.*;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
@@ -37,28 +38,91 @@
 import java.security.AccessController;
 import java.security.CodeSource;
 import jdk.internal.misc.SharedSecrets;
-import sun.security.action.GetPropertyAction;
 import sun.security.util.ManifestEntryVerifier;
 import sun.security.util.SignatureFileVerifier;
 
+import static java.util.jar.Attributes.Name.MULTI_RELEASE;
+
 /**
  * The {@code JarFile} class is used to read the contents of a jar file
  * from any file that can be opened with {@code java.io.RandomAccessFile}.
  * It extends the class {@code java.util.zip.ZipFile} with support
- * for reading an optional {@code Manifest} entry. The
- * {@code Manifest} can be used to specify meta-information about the
- * jar file and its entries.
+ * for reading an optional {@code Manifest} entry, and support for
+ * processing multi-release jar files.  The {@code Manifest} can be used
+ * to specify meta-information about the jar file and its entries.
+ *
+ * <p>A multi-release jar file is a jar file that contains
+ * a manifest with a main attribute named "Multi-Release",
+ * a set of "base" entries, some of which are public classes with public
+ * or protected methods that comprise the public interface of the jar file,
+ * and a set of "versioned" entries contained in subdirectories of the
+ * "META-INF/versions" directory.  The versioned entries are partitioned by the
+ * major version of the Java platform.  A versioned entry, with a version
+ * {@code n}, {@code 8 < n}, in the "META-INF/versions/{n}" directory overrides
+ * the base entry as well as any entry with a version number {@code i} where
+ * {@code 8 < i < n}.
+ *
+ * <p>By default, a {@code JarFile} for a multi-release jar file is configured
+ * to process the multi-release jar file as if it were a plain (unversioned) jar
+ * file, and as such an entry name is associated with at most one base entry.
+ * The {@code JarFile} may be configured to process a multi-release jar file by
+ * creating the {@code JarFile} with the
+ * {@link JarFile#JarFile(File, boolean, int, Release)} constructor.  The
+ * {@code Release} object sets a maximum version used when searching for
+ * versioned entries.  When so configured, an entry name
+ * can correspond with at most one base entry and zero or more versioned
+ * entries. A search is required to associate the entry name with the latest
+ * versioned entry whose version is less than or equal to the maximum version
+ * (see {@link #getEntry(String)}).
+ *
+ * <p>Class loaders that utilize {@code JarFile} to load classes from the
+ * contents of {@code JarFile} entries should construct the {@code JarFile}
+ * by invoking the {@link JarFile#JarFile(File, boolean, int, Release)}
+ * constructor with the value {@code Release.RUNTIME} assigned to the last
+ * argument.  This assures that classes compatible with the major
+ * version of the running JVM are loaded from multi-release jar files.
+ *
+ * <p>If the verify flag is on when opening a signed jar file, the content of
+ * the file is verified against its signature embedded inside the file. Please
+ * note that the verification process does not include validating the signer's
+ * certificate. A caller should inspect the return value of
+ * {@link JarEntry#getCodeSigners()} to further determine if the signature
+ * can be trusted.
  *
  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
  * or method in this class will cause a {@link NullPointerException} to be
  * thrown.
  *
- * If the verify flag is on when opening a signed jar file, the content of the
- * file is verified against its signature embedded inside the file. Please note
- * that the verification process does not include validating the signer's
- * certificate. A caller should inspect the return value of
- * {@link JarEntry#getCodeSigners()} to further determine if the signature
- * can be trusted.
+ * @implNote
+ * <div class="block">
+ * If the API can not be used to configure a {@code JarFile} (e.g. to override
+ * the configuration of a compiled application or library), two {@code System}
+ * properties are available.
+ * <ul>
+ * <li>
+ * {@code jdk.util.jar.version} can be assigned a value that is the
+ * {@code String} representation of a non-negative integer
+ * {@code <= Version.current().major()}.  The value is used to set the effective
+ * runtime version to something other than the default value obtained by
+ * evaluating {@code Version.current().major()}. The effective runtime version
+ * is the version that the {@link JarFile#JarFile(File, boolean, int, Release)}
+ * constructor uses when the value of the last argument is
+ * {@code Release.RUNTIME}.
+ * </li>
+ * <li>
+ * {@code jdk.util.jar.enableMultiRelease} can be assigned one of the three
+ * {@code String} values <em>true</em>, <em>false</em>, or <em>force</em>.  The
+ * value <em>true</em>, the default value, enables multi-release jar file
+ * processing.  The value <em>false</em> disables multi-release jar processing,
+ * ignoring the "Multi-Release" manifest attribute, and the versioned
+ * directories in a multi-release jar file if they exist.  Furthermore,
+ * the method {@link JarFile#isMultiRelease()} returns <em>false</em>. The value
+ * <em>force</em> causes the {@code JarFile} to be initialized to runtime
+ * versioning after construction.  It effectively does the same as this code:
+ * {@code (new JarFile(File, boolean, int, Release.RUNTIME)}.
+ * </li>
+ * </ul>
+ * </div>
  *
  * @author  David Connelly
  * @see     Manifest
@@ -68,26 +132,126 @@
  */
 public
 class JarFile extends ZipFile {
+    private final static int BASE_VERSION;
+    private final static int RUNTIME_VERSION;
+    private final static boolean MULTI_RELEASE_ENABLED;
+    private final static boolean MULTI_RELEASE_FORCED;
     private SoftReference<Manifest> manRef;
     private JarEntry manEntry;
     private JarVerifier jv;
     private boolean jvInitialized;
     private boolean verify;
+    private final int version;
+    private boolean notVersioned;
+    private final boolean runtimeVersioned;
 
     // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true)
     private boolean hasClassPathAttribute;
     // true if manifest checked for special attributes
     private volatile boolean hasCheckedSpecialAttributes;
 
-    // Set up JavaUtilJarAccess in SharedSecrets
     static {
+        // Set up JavaUtilJarAccess in SharedSecrets
         SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
+
+        BASE_VERSION = 8;  // one less than lowest version for versioned entries
+        RUNTIME_VERSION = AccessController.doPrivileged(
+                new PrivilegedAction<Integer>() {
+                    public Integer run() {
+                        Integer v = sun.misc.Version.jdkMajorVersion(); // fixme when JEP 223 Version integrated
+                        Integer i = Integer.getInteger("jdk.util.jar.version", v);
+                        i = i < 0 ? 0 : i;
+                        return i > v ? v : i;
+                    }
+                }
+        );
+        String multi_release = AccessController.doPrivileged(
+                new PrivilegedAction<String>() {
+                    public String run() {
+                        return System.getProperty("jdk.util.jar.enableMultiRelease", "true");
+                    }
+                }
+        );
+        switch (multi_release) {
+            case "true":
+            default:
+                MULTI_RELEASE_ENABLED = true;
+                MULTI_RELEASE_FORCED = false;
+                break;
+            case "false":
+                MULTI_RELEASE_ENABLED = false;
+                MULTI_RELEASE_FORCED = false;
+                break;
+            case "force":
+                MULTI_RELEASE_ENABLED = true;
+                MULTI_RELEASE_FORCED = true;
+                break;
+        }
     }
 
     /**
+     * A set of constants that represent the entries in either the base directory
+     * or one of the versioned directories in a multi-release jar file.  It's
+     * possible for a multi-release jar file to contain versioned directories
+     * that are not represented by the constants of the {@code Release} enum.
+     * In those cases, the entries will not be located by this {@code JarFile}
+     * through the aliasing mechanism, but they can be directly accessed by
+     * specifying the full path name of the entry.
+     *
+     * @since 9
+     */
+    public enum Release {
+        /**
+         * Represents unversioned entries, or entries in "regular", as opposed
+         * to multi-release jar files.
+         */
+        BASE(BASE_VERSION),
+
+        /**
+         * Represents entries found in the META-INF/versions/9 directory of a
+         * multi-release jar file.
+         */
+        VERSION_9(9),
+
+        // fill in the "blanks" for future releases
+
+        /**
+         * Represents entries found in the META-INF/versions/{n} directory of a
+         * multi-release jar file, where {@code n} is the effective runtime
+         * version of the jar file.
+         *
+         * @implNote
+         * <div class="block">
+         * The effective runtime version is determined
+         * by evaluating {@code Version.current().major()} or by using the value
+         * of the {@code jdk.util.jar.version} System property if it exists.
+         * </div>
+         */
+        RUNTIME(RUNTIME_VERSION);
+
+        Release(int version) {
+            this.version = version;
+        }
+
+        private static Release valueOf(int version) {
+            return version <= BASE.value() ? BASE : valueOf("VERSION_" + version);
+        }
+
+        private final int version;
+
+        private int value() {
+            return this.version;
+        }
+    }
+
+    private static final String META_INF = "META-INF/";
+
+    private static final String META_INF_VERSIONS = META_INF + "versions/";
+
+    /**
      * The JAR manifest file name.
      */
-    public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+    public static final String MANIFEST_NAME = META_INF + "MANIFEST.MF";
 
     /**
      * Creates a new {@code JarFile} to read from the specified
@@ -129,7 +293,6 @@
         this(file, true, ZipFile.OPEN_READ);
     }
 
-
     /**
      * Creates a new {@code JarFile} to read from the specified
      * {@code File} object.
@@ -144,7 +307,6 @@
         this(file, verify, ZipFile.OPEN_READ);
     }
 
-
     /**
      * Creates a new {@code JarFile} to read from the specified
      * {@code File} object in the specified mode.  The mode argument
@@ -162,10 +324,104 @@
      * @since 1.3
      */
     public JarFile(File file, boolean verify, int mode) throws IOException {
+        this(file, verify, mode, Release.BASE);
+        this.notVersioned = true;
+    }
+
+    /**
+     * Creates a new {@code JarFile} to read from the specified
+     * {@code File} object in the specified mode.  The mode argument
+     * must be either {@code OPEN_READ} or {@code OPEN_READ | OPEN_DELETE}.
+     * The version argument configures the {@code JarFile} for processing
+     * multi-release jar files.
+     *
+     * @param file the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @param mode the mode in which the file is to be opened
+     * @param version specifies the release version for a multi-release jar file
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalArgumentException
+     *         if the {@code mode} argument is invalid
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     * @throws NullPointerException if {@code version} is {@code null}
+     * @since 9
+     */
+    public JarFile(File file, boolean verify, int mode, Release version) throws IOException {
         super(file, mode);
+        Objects.requireNonNull(version);
         this.verify = verify;
+        // version applies to multi-release jar files, ignored for regular jar files
+        this.version = MULTI_RELEASE_FORCED ? RUNTIME_VERSION : version.value();
+        this.runtimeVersioned = version == Release.RUNTIME;
+        assert runtimeVersionExists();
     }
 
+    private boolean runtimeVersionExists() {
+        int version = sun.misc.Version.jdkMajorVersion();  // fixme when JEP 223 integrated
+        try {
+            Release.valueOf(version);
+            return true;
+        } catch (IllegalArgumentException x) {
+            System.err.println("No JarFile.Release object for release " + version);
+            return false;
+        }
+    }
+
+    /**
+     * Returns the maximum version used when searching for versioned entries.
+     *
+     * @return the maximum version, or {@code Release.BASE} if this jar file is
+     *         processed as if it is an unversioned jar file or is not a
+     *         multi-release jar file
+     * @since 9
+     */
+    public final Release getVersion() {
+        if (isMultiRelease()) {
+            return runtimeVersioned ? Release.RUNTIME : Release.valueOf(version);
+        } else {
+            return Release.BASE;
+        }
+    }
+
+    /**
+     * Indicates whether or not this jar file is a multi-release jar file.
+     *
+     * @return true if this JarFile is a multi-release jar file
+     * @since 9
+     */
+    public final boolean isMultiRelease() {
+        // do not call this code in a constructor because some subclasses use
+        // lazy loading of manifest so it won't be available at construction time
+        if (MULTI_RELEASE_ENABLED) {
+            // Doubled-checked locking pattern
+            Boolean result = isMultiRelease;
+            if (result == null) {
+                synchronized (this) {
+                    result = isMultiRelease;
+                    if (result == null) {
+                        Manifest man = null;
+                        try {
+                            man = getManifest();
+                        } catch (IOException e) {
+                            //Ignored, manifest cannot be read
+                        }
+                        isMultiRelease = result = (man != null)
+                                && man.getMainAttributes().containsKey(MULTI_RELEASE)
+                                ? Boolean.TRUE : Boolean.FALSE;
+                    }
+                }
+            }
+            return result == Boolean.TRUE;
+        } else {
+            return false;
+        }
+    }
+    // the following field, isMultiRelease, should only be used in the method
+    // isMultiRelease(), like a static local
+    private volatile Boolean isMultiRelease;    // is jar multi-release?
+
     /**
      * Returns the jar file manifest, or {@code null} if none.
      *
@@ -209,40 +465,87 @@
     }
 
     /**
-     * Returns the {@code JarEntry} for the given entry name or
+     * Returns the {@code JarEntry} for the given base entry name or
      * {@code null} if not found.
      *
+     * <p>If this {@code JarFile} is a multi-release jar file and is configured
+     * to be processed as such, then a search is performed to find and return
+     * a {@code JarEntry} that is the latest versioned entry associated with the
+     * given entry name.  The returned {@code JarEntry} is the versioned entry
+     * corresponding to the given base entry name prefixed with the string
+     * {@code "META-INF/versions/{n}/"}, for the largest value of {@code n} for
+     * which an entry exists.  If such a versioned entry does not exist, then
+     * the {@code JarEntry} for the base entry is returned, otherwise
+     * {@code null} is returned if no entries are found.  The initial value for
+     * the version {@code n} is the maximum version as returned by the method
+     * {@link JarFile#getVersion()}.
+     *
      * @param name the jar file entry name
-     * @return the {@code JarEntry} for the given entry name or
-     *         {@code null} if not found.
+     * @return the {@code JarEntry} for the given entry name, or
+     *         the versioned entry name, or {@code null} if not found
      *
      * @throws IllegalStateException
      *         may be thrown if the jar file has been closed
      *
      * @see java.util.jar.JarEntry
+     *
+     * @implSpec
+     * <div class="block">
+     * This implementation invokes {@link JarFile#getEntry(String)}.
+     * </div>
      */
     public JarEntry getJarEntry(String name) {
         return (JarEntry)getEntry(name);
     }
 
     /**
-     * Returns the {@code ZipEntry} for the given entry name or
+     * Returns the {@code ZipEntry} for the given base entry name or
      * {@code null} if not found.
      *
+     * <p>If this {@code JarFile} is a multi-release jar file and is configured
+     * to be processed as such, then a search is performed to find and return
+     * a {@code ZipEntry} that is the latest versioned entry associated with the
+     * given entry name.  The returned {@code ZipEntry} is the versioned entry
+     * corresponding to the given base entry name prefixed with the string
+     * {@code "META-INF/versions/{n}/"}, for the largest value of {@code n} for
+     * which an entry exists.  If such a versioned entry does not exist, then
+     * the {@code ZipEntry} for the base entry is returned, otherwise
+     * {@code null} is returned if no entries are found.  The initial value for
+     * the version {@code n} is the maximum version as returned by the method
+     * {@link JarFile#getVersion()}.
+     *
      * @param name the jar file entry name
      * @return the {@code ZipEntry} for the given entry name or
-     *         {@code null} if not found
+     *         the versioned entry name or {@code null} if not found
      *
      * @throws IllegalStateException
      *         may be thrown if the jar file has been closed
      *
      * @see java.util.zip.ZipEntry
+     *
+     * @implSpec
+     * <div class="block">
+     * This implementation may return a versioned entry for the requested name
+     * even if there is not a corresponding base entry.  This can occur
+     * if there is a private or package-private versioned entry that matches.
+     * If a subclass overrides this method, assure that the override method
+     * invokes {@code super.getEntry(name)} to obtain all versioned entries.
+     * </div>
      */
     public ZipEntry getEntry(String name) {
         ZipEntry ze = super.getEntry(name);
         if (ze != null) {
             return new JarFileEntry(ze);
         }
+        // no matching base entry, but maybe there is a versioned entry,
+        // like a new private class
+        if (isMultiRelease()) {
+            ze = new ZipEntry(name);
+            ZipEntry vze = getVersionedEntry(ze);
+            if (ze != vze) {
+                return new JarFileEntry(name, vze);
+            }
+        }
         return null;
     }
 
@@ -250,14 +553,42 @@
             Iterator<JarEntry>
     {
         final Enumeration<? extends ZipEntry> e = JarFile.super.entries();
+        ZipEntry ze;
 
         public boolean hasNext() {
-            return e.hasMoreElements();
+            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;
         }
 
         public JarEntry next() {
-            ZipEntry ze = e.nextElement();
-            return new JarFileEntry(ze);
+            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();
         }
 
         public boolean hasMoreElements() {
@@ -274,7 +605,19 @@
     }
 
     /**
-     * Returns an enumeration of the jar file entries.
+     * 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/".
      *
      * @return an enumeration of the jar file entries
      * @throws IllegalStateException
@@ -285,10 +628,21 @@
     }
 
     /**
-     * Returns an ordered {@code Stream} over the jar file entries.
+     * Returns an ordered {@code Stream} over all the jar file entries.
      * Entries appear in the {@code Stream} in the order they appear in
-     * the central directory of the jar file.
-     *
+     * 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/".
      * @return an ordered {@code Stream} of entries in this jar file
      * @throws IllegalStateException if the jar file has been closed
      * @since 1.8
@@ -300,14 +654,44 @@
                         Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
     }
 
+    private ZipEntry searchForVersionedEntry(final int version, String name) {
+        ZipEntry vze = null;
+        String sname = "/" + name;
+        int i = version;
+        while (i > BASE_VERSION) {
+            vze = super.getEntry(META_INF_VERSIONS + i + sname);
+            if (vze != null) break;
+            i--;
+        }
+        return vze;
+    }
+
+    private ZipEntry getVersionedEntry(ZipEntry ze) {
+        ZipEntry vze = null;
+        if (version > BASE_VERSION && !ze.isDirectory()) {
+            String name = ze.getName();
+            if (!name.startsWith(META_INF)) {
+                vze = searchForVersionedEntry(version, name);
+            }
+        }
+        return vze == null ? ze : vze;
+    }
+
     private class JarFileEntry extends JarEntry {
+        final private String name;
+
         JarFileEntry(ZipEntry ze) {
-            super(ze);
+            super(isMultiRelease() ? getVersionedEntry(ze) : ze);
+            this.name = ze.getName();
+        }
+        JarFileEntry(String name, ZipEntry vze) {
+            super(vze);
+            this.name = name;
         }
         public Attributes getAttributes() throws IOException {
             Manifest man = JarFile.this.getManifest();
             if (man != null) {
-                return man.getAttributes(getName());
+                return man.getAttributes(super.getName());
             } else {
                 return null;
             }
@@ -319,7 +703,7 @@
                 throw new RuntimeException(e);
             }
             if (certs == null && jv != null) {
-                certs = jv.getCerts(JarFile.this, this);
+                certs = jv.getCerts(JarFile.this, reifiedEntry());
             }
             return certs == null ? null : certs.clone();
         }
@@ -330,10 +714,22 @@
                 throw new RuntimeException(e);
             }
             if (signers == null && jv != null) {
-                signers = jv.getCodeSigners(JarFile.this, this);
+                signers = jv.getCodeSigners(JarFile.this, reifiedEntry());
             }
             return signers == null ? null : signers.clone();
         }
+        JarFileEntry reifiedEntry() {
+            if (isMultiRelease()) {
+                String entryName = super.getName();
+                return entryName.equals(this.name) ? this : new JarFileEntry(entryName, this);
+            }
+            return this;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
     }
 
     /*
@@ -491,12 +887,19 @@
         // wrap a verifier stream around the real stream
         return new JarVerifier.VerifierStream(
             getManifestFromReference(),
-            ze instanceof JarFileEntry ?
-            (JarEntry) ze : getJarEntry(ze.getName()),
+            verifiableEntry(ze),
             super.getInputStream(ze),
             jv);
     }
 
+    private JarEntry verifiableEntry(ZipEntry ze) {
+        if (!(ze instanceof JarFileEntry)) {
+            ze = getJarEntry(ze.getName());
+        }
+        // assure the name and entry match for verification
+        return ze == null ? null : ((JarFileEntry)ze).reifiedEntry();
+    }
+
     // Statics for hand-coded Boyer-Moore search
     private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'};
     // The bad character shift for "class-path"
@@ -523,7 +926,7 @@
     private JarEntry getManEntry() {
         if (manEntry == null) {
             // First look up manifest entry using standard name
-            manEntry = getJarEntry(MANIFEST_NAME);
+            ZipEntry manEntry = super.getEntry(MANIFEST_NAME);
             if (manEntry == null) {
                 // If not found, then iterate through all the "META-INF/"
                 // entries to find a match.
@@ -531,12 +934,15 @@
                 if (names != null) {
                     for (String name : names) {
                         if (MANIFEST_NAME.equals(name.toUpperCase(Locale.ENGLISH))) {
-                            manEntry = getJarEntry(name);
+                            manEntry = super.getEntry(name);
                             break;
                         }
                     }
                 }
             }
+            this.manEntry = (manEntry == null)
+                    ? null
+                    : new JarFileEntry(manEntry.getName(), manEntry);
         }
         return manEntry;
     }
--- a/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, 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
@@ -64,8 +64,7 @@
     private static final Map<Provider, Object> verifyingProviders =
             new IdentityHashMap<>();
 
-    // Set the default value. May be changed in the static initializer.
-    private static boolean isRestricted = true;
+    private static final boolean isRestricted;
 
     /*
      * Don't let anyone instantiate this.
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Signal.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Signal.java	Wed Jul 05 21:24:14 2017 +0200
@@ -279,6 +279,11 @@
         public void handle(Signal sig) {
             throw new UnsupportedOperationException("invoking native signal handle not supported");
         }
+
+        public String toString() {
+            return this == SIG_DFL ? "SIG_DFL" :
+                    (this == SIG_IGN ? "SIG_IGN" : super.toString());
+        }
     }
 
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -458,6 +458,78 @@
         copyMemory(null, srcAddress, null, destAddress, bytes);
     }
 
+    private boolean isPrimitiveArray(Class<?> c) {
+        Class<?> componentType = c.getComponentType();
+        return componentType != null && componentType.isPrimitive();
+    }
+
+    private native void copySwapMemory0(Object srcBase, long srcOffset,
+                                        Object destBase, long destOffset,
+                                        long bytes, long elemSize);
+
+    /**
+     * Copies all elements from one block of memory to another block,
+     * *unconditionally* byte swapping the elements on the fly.
+     *
+     * <p>This method determines each block's base address by means of two parameters,
+     * and so it provides (in effect) a <em>double-register</em> addressing mode,
+     * as discussed in {@link #getInt(Object,long)}.  When the object reference is null,
+     * the offset supplies an absolute base address.
+     *
+     * @since 9
+     */
+    public void copySwapMemory(Object srcBase, long srcOffset,
+                               Object destBase, long destOffset,
+                               long bytes, long elemSize) {
+        if (bytes < 0) {
+            throw new IllegalArgumentException();
+        }
+        if (elemSize != 2 && elemSize != 4 && elemSize != 8) {
+            throw new IllegalArgumentException();
+        }
+        if (bytes % elemSize != 0) {
+            throw new IllegalArgumentException();
+        }
+        if ((srcBase == null && srcOffset == 0) ||
+            (destBase == null && destOffset == 0)) {
+            throw new NullPointerException();
+        }
+
+        // Must be off-heap, or primitive heap arrays
+        if (srcBase != null && (srcOffset < 0 || !isPrimitiveArray(srcBase.getClass()))) {
+            throw new IllegalArgumentException();
+        }
+        if (destBase != null && (destOffset < 0 || !isPrimitiveArray(destBase.getClass()))) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sanity check size and offsets on 32-bit platforms. Most
+        // significant 32 bits must be zero.
+        if (ADDRESS_SIZE == 4 &&
+            (bytes >>> 32 != 0 || srcOffset >>> 32 != 0 || destOffset >>> 32 != 0)) {
+            throw new IllegalArgumentException();
+        }
+
+        if (bytes == 0) {
+            return;
+        }
+
+        copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
+    }
+
+   /**
+     * Copies all elements from one block of memory to another block, byte swapping the
+     * elements on the fly.
+     *
+     * This provides a <em>single-register</em> addressing mode, as
+     * discussed in {@link #getInt(Object,long)}.
+     *
+     * Equivalent to {@code copySwapMemory(null, srcAddress, null, destAddress, bytes, elemSize)}.
+     */
+    public void copySwapMemory(long srcAddress, long destAddress, long bytes, long elemSize) {
+        copySwapMemory(null, srcAddress, null, destAddress, bytes, elemSize);
+    }
+
     /**
      * Disposes of a block of native memory, as obtained from {@link
      * #allocateMemory} or {@link #reallocateMemory}.  The address passed to
@@ -1159,7 +1231,12 @@
     /** @see #getLongUnaligned(Object, long) */
     @HotSpotIntrinsicCandidate
     public final char getCharUnaligned(Object o, long offset) {
-        return (char)getShortUnaligned(o, offset);
+        if ((offset & 1) == 0) {
+            return getChar(o, offset);
+        } else {
+            return (char)makeShort(getByte(o, offset),
+                                   getByte(o, offset + 1));
+        }
     }
 
     /** @see #getLongUnaligned(Object, long, boolean) */
--- a/jdk/src/java.base/share/classes/jdk/net/Sockets.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/jdk/net/Sockets.java	Wed Jul 05 21:24:14 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
@@ -251,9 +251,23 @@
         }
     }
 
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
+
+    /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
     private static void initOptionSets() {
         boolean flowsupported = ExtendedOptionsImpl.flowSupported();
-
+        boolean reuseportsupported = isReusePortAvailable();
         // Socket
 
         Set<SocketOption<?>> set = new HashSet<>();
@@ -261,6 +275,9 @@
         set.add(StandardSocketOptions.SO_SNDBUF);
         set.add(StandardSocketOptions.SO_RCVBUF);
         set.add(StandardSocketOptions.SO_REUSEADDR);
+        if (reuseportsupported) {
+            set.add(StandardSocketOptions.SO_REUSEPORT);
+        }
         set.add(StandardSocketOptions.SO_LINGER);
         set.add(StandardSocketOptions.IP_TOS);
         set.add(StandardSocketOptions.TCP_NODELAY);
@@ -275,6 +292,9 @@
         set = new HashSet<>();
         set.add(StandardSocketOptions.SO_RCVBUF);
         set.add(StandardSocketOptions.SO_REUSEADDR);
+        if (reuseportsupported) {
+            set.add(StandardSocketOptions.SO_REUSEPORT);
+        }
         set.add(StandardSocketOptions.IP_TOS);
         set = Collections.unmodifiableSet(set);
         options.put(ServerSocket.class, set);
@@ -285,6 +305,9 @@
         set.add(StandardSocketOptions.SO_SNDBUF);
         set.add(StandardSocketOptions.SO_RCVBUF);
         set.add(StandardSocketOptions.SO_REUSEADDR);
+        if (reuseportsupported) {
+            set.add(StandardSocketOptions.SO_REUSEPORT);
+        }
         set.add(StandardSocketOptions.IP_TOS);
         if (flowsupported) {
             set.add(ExtendedSocketOptions.SO_FLOW_SLA);
@@ -298,6 +321,9 @@
         set.add(StandardSocketOptions.SO_SNDBUF);
         set.add(StandardSocketOptions.SO_RCVBUF);
         set.add(StandardSocketOptions.SO_REUSEADDR);
+        if (reuseportsupported) {
+            set.add(StandardSocketOptions.SO_REUSEPORT);
+        }
         set.add(StandardSocketOptions.IP_TOS);
         set.add(StandardSocketOptions.IP_MULTICAST_IF);
         set.add(StandardSocketOptions.IP_MULTICAST_TTL);
@@ -308,4 +334,6 @@
         set = Collections.unmodifiableSet(set);
         options.put(MulticastSocket.class, set);
     }
+
+    private static native boolean isReusePortAvailable0();
 }
--- a/jdk/src/java.base/share/classes/sun/misc/URLClassPath.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/misc/URLClassPath.java	Wed Jul 05 21:24:14 2017 +0200
@@ -63,6 +63,7 @@
 import java.util.jar.Manifest;
 import java.util.jar.Attributes;
 import java.util.jar.Attributes.Name;
+import java.util.zip.ZipFile;
 
 import jdk.internal.jimage.ImageLocation;
 import jdk.internal.jimage.ImageReader;
@@ -727,9 +728,10 @@
                 if (!p.exists()) {
                     throw new FileNotFoundException(p.getPath());
                 }
-                return checkJar(new JarFile(p.getPath()));
+                return checkJar(new JarFile(new File(p.getPath()), true, ZipFile.OPEN_READ,
+                        JarFile.Release.RUNTIME));
             }
-            URLConnection uc = getBaseURL().openConnection();
+            URLConnection uc = (new URL(getBaseURL(), "#runtime")).openConnection();
             uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION);
             JarFile jarFile = ((JarURLConnection)uc).getJarFile();
             return checkJar(jarFile);
@@ -756,7 +758,9 @@
 
             final URL url;
             try {
-                url = new URL(getBaseURL(), ParseUtil.encodePath(name, false));
+                // add #runtime fragment to tell JarURLConnection to use
+                // runtime versioning if the underlying jar file is multi-release
+                url = new URL(getBaseURL(), ParseUtil.encodePath(name, false) + "#runtime");
                 if (check) {
                     URLClassPath.check(url);
                 }
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java	Wed Jul 05 21:24:14 2017 +0200
@@ -65,9 +65,10 @@
     }
 
     static JarFile getJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
-        if (isFileURL(url))
-            return new URLJarFile(url, closeController);
-        else {
+        if (isFileURL(url)) {
+            Release version = "runtime".equals(url.getRef()) ? Release.RUNTIME : Release.BASE;
+            return new URLJarFile(url, closeController, version);
+        } else {
             return retrieve(url, closeController);
         }
     }
@@ -89,8 +90,13 @@
         this.closeController = closeController;
     }
 
-    private URLJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
-        super(ParseUtil.decode(url.getFile()));
+    private URLJarFile(File file, URLJarFileCloseController closeController, Release version) throws IOException {
+        super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE, version);
+        this.closeController = closeController;
+    }
+
+    private URLJarFile(URL url, URLJarFileCloseController closeController, Release version) throws IOException {
+        super(new File(ParseUtil.decode(url.getFile())), true, ZipFile.OPEN_READ, version);
         this.closeController = closeController;
     }
 
@@ -179,14 +185,6 @@
      * Given a URL, retrieves a JAR file, caches it to disk, and creates a
      * cached JAR file object.
      */
-    private static JarFile retrieve(final URL url) throws IOException {
-        return retrieve(url, null);
-    }
-
-    /**
-     * Given a URL, retrieves a JAR file, caches it to disk, and creates a
-     * cached JAR file object.
-     */
      private static JarFile retrieve(final URL url, final URLJarFileCloseController closeController) throws IOException {
         /*
          * See if interface is set, then call retrieve function of the class
@@ -202,6 +200,7 @@
         {
 
             JarFile result = null;
+            Release version = "runtime".equals(url.getRef()) ? Release.RUNTIME : Release.BASE;
 
             /* get the stream before asserting privileges */
             try (final InputStream in = url.openConnection().getInputStream()) {
@@ -211,7 +210,7 @@
                             Path tmpFile = Files.createTempFile("jar_cache", null);
                             try {
                                 Files.copy(in, tmpFile, StandardCopyOption.REPLACE_EXISTING);
-                                JarFile jarFile = new URLJarFile(tmpFile.toFile(), closeController);
+                                JarFile jarFile = new URLJarFile(tmpFile.toFile(), closeController, version);
                                 tmpFile.toFile().deleteOnExit();
                                 return jarFile;
                             } catch (Throwable thr) {
--- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, 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
@@ -231,6 +231,9 @@
             HashSet<SocketOption<?>> set = new HashSet<>(2);
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             return Collections.unmodifiableSet(set);
         }
     }
--- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, 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
@@ -508,6 +508,9 @@
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_KEEPALIVE);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             set.add(StandardSocketOptions.TCP_NODELAY);
             if (ExtendedOptionsImpl.flowSupported()) {
                 set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
--- a/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, 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
@@ -298,6 +298,9 @@
             set.add(StandardSocketOptions.SO_SNDBUF);
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             set.add(StandardSocketOptions.SO_BROADCAST);
             set.add(StandardSocketOptions.IP_TOS);
             set.add(StandardSocketOptions.IP_MULTICAST_IF);
--- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -56,6 +56,8 @@
 
     private static volatile boolean checkedIPv6;
     private static volatile boolean isIPv6Available;
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
 
     /**
      * Tells whether dual-IPv4/IPv6 sockets should be used.
@@ -69,6 +71,17 @@
     }
 
     /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
+    /**
      * Returns true if exclusive binding is on
      */
     static boolean useExclusiveBind() {
@@ -389,6 +402,8 @@
 
     private static native boolean isIPv6Available0();
 
+    private static native boolean isReusePortAvailable0();
+
     /*
      * Returns 1 for Windows and -1 for Solaris/Linux/Mac OS
      */
--- a/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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,7 +33,6 @@
 import java.util.*;
 import sun.net.NetHooks;
 
-
 /**
  * An implementation of ServerSocketChannels
  */
@@ -185,6 +184,9 @@
             HashSet<SocketOption<?>> set = new HashSet<>(2);
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             set.add(StandardSocketOptions.IP_TOS);
             return Collections.unmodifiableSet(set);
         }
--- a/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -234,6 +234,9 @@
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_KEEPALIVE);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             set.add(StandardSocketOptions.SO_LINGER);
             set.add(StandardSocketOptions.TCP_NODELAY);
             // additional options required by socket adaptor
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Wed Jul 05 21:24:14 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
@@ -81,9 +81,6 @@
 
     private boolean serverKeyExchangeReceived;
 
-    private final boolean enableStatusRequestExtension =
-            Debug.getBooleanProperty(
-                    "jdk.tls.client.enableStatusRequestExtension", true);
     private boolean staplingActive = false;
     private X509Certificate[] deferredCerts;
 
@@ -761,7 +758,7 @@
                     type == ExtensionType.EXT_STATUS_REQUEST_V2) {
                 // Only enable the stapling feature if the client asserted
                 // these extensions.
-                if (enableStatusRequestExtension) {
+                if (sslContext.isStaplingEnabled(true)) {
                     staplingActive = true;
                 } else {
                     fatalSE(Alerts.alert_unexpected_message, "Server set " +
@@ -1562,7 +1559,7 @@
         }
 
         // Add status_request and status_request_v2 extensions
-        if (enableStatusRequestExtension) {
+        if (sslContext.isStaplingEnabled(true)) {
             clientHelloMessage.addCertStatusReqListV2Extension();
             clientHelloMessage.addCertStatusRequestExtension();
         }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Wed Jul 05 21:24:14 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
@@ -55,7 +55,11 @@
     // DTLS cookie exchange manager
     private volatile HelloCookieManager helloCookieManager;
 
-    private StatusResponseManager statusResponseManager;
+    private final boolean clientEnableStapling = Debug.getBooleanProperty(
+            "jdk.tls.client.enableStatusRequestExtension", true);
+    private final boolean serverEnableStapling = Debug.getBooleanProperty(
+            "jdk.tls.server.enableStatusRequestExtension", false);
+    private volatile StatusResponseManager statusResponseManager;
 
     SSLContextImpl() {
         ephemeralKeyManager = new EphemeralKeyManager();
@@ -80,7 +84,6 @@
             }
         }
         trustManager = chooseTrustManager(tm);
-        statusResponseManager = new StatusResponseManager();
 
         if (sr == null) {
             secureRandom = JsseJce.getSecureRandom();
@@ -258,6 +261,18 @@
     }
 
     StatusResponseManager getStatusResponseManager() {
+        if (serverEnableStapling && statusResponseManager == null) {
+            synchronized (this) {
+                if (statusResponseManager == null) {
+                    if (debug != null && Debug.isOn("sslctx")) {
+                        System.out.println(
+                                "Initializing StatusResponseManager");
+                    }
+                    statusResponseManager = new StatusResponseManager();
+                }
+            }
+        }
+
         return statusResponseManager;
     }
 
@@ -309,6 +324,18 @@
                (cipherSuites == getClientDefaultCipherSuiteList());
     }
 
+    /**
+     * Return whether client or server side stapling has been enabled
+     * for this SSLContextImpl
+     * @param isClient true if the caller is operating in a client side role,
+     * false if acting as a server.
+     * @return true if stapling has been enabled for the specified role, false
+     * otherwise.
+     */
+    boolean isStaplingEnabled(boolean isClient) {
+        return isClient ? clientEnableStapling : serverEnableStapling;
+    }
+
     /*
      * Return the list of all available CipherSuites with a priority of
      * minPriority or above.
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Wed Jul 05 21:24:14 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
@@ -118,10 +118,6 @@
                     LegacyAlgorithmConstraints.PROPERTY_TLS_LEGACY_ALGS,
                     new SSLAlgorithmDecomposer());
 
-    // To switch off the status_request[_v2] extensions
-    private static final boolean enableStatusRequestExtension =
-            Debug.getBooleanProperty(
-                    "jdk.tls.server.enableStatusRequestExtension", false);
     private boolean staplingActive = false;
     private long statusRespTimeout;
 
@@ -589,7 +585,7 @@
                 (CertStatusReqListV2Extension)mesg.extensions.get(
                         ExtensionType.EXT_STATUS_REQUEST_V2);
         // Keep stapling active if at least one of the extensions has been set
-        staplingActive = enableStatusRequestExtension &&
+        staplingActive = sslContext.isStaplingEnabled(false) &&
                 (statReqExt != null || statReqExtV2 != null);
 
         /*
@@ -932,19 +928,32 @@
             }
 
             if (statReqType != null && statReqData != null) {
-                // Next, attempt to obtain status responses
                 StatusResponseManager statRespMgr =
                         sslContext.getStatusResponseManager();
-                responseMap = statRespMgr.get(statReqType, statReqData, certs,
-                        statusRespTimeout, TimeUnit.MILLISECONDS);
-                if (!responseMap.isEmpty()) {
-                    // We now can safely assert status_request[_v2] in our
-                    // ServerHello, and know for certain that we can provide
-                    // responses back to this client for this connection.
-                    if (statusRespExt == ExtensionType.EXT_STATUS_REQUEST) {
-                        m1.extensions.add(new CertStatusReqExtension());
-                    } else if (statusRespExt == ExtensionType.EXT_STATUS_REQUEST_V2) {
-                        m1.extensions.add(new CertStatusReqListV2Extension());
+                if (statRespMgr != null) {
+                    responseMap = statRespMgr.get(statReqType, statReqData,
+                            certs, statusRespTimeout, TimeUnit.MILLISECONDS);
+                    if (!responseMap.isEmpty()) {
+                        // We now can safely assert status_request[_v2] in our
+                        // ServerHello, and know for certain that we can provide
+                        // responses back to this client for this connection.
+                        if (statusRespExt == ExtensionType.EXT_STATUS_REQUEST) {
+                            m1.extensions.add(new CertStatusReqExtension());
+                        } else if (statusRespExt ==
+                                ExtensionType.EXT_STATUS_REQUEST_V2) {
+                            m1.extensions.add(
+                                    new CertStatusReqListV2Extension());
+                        }
+                    }
+                } else {
+                    // This should not happen if stapling is active, but
+                    // if lazy initialization of the StatusResponseManager
+                    // doesn't occur we should turn off stapling.
+                    if (debug != null && Debug.isOn("handshake")) {
+                        System.out.println("Warning: lazy initialization " +
+                                "of the StatusResponseManager failed.  " +
+                                "Stapling has been disabled.");
+                        staplingActive = false;
                     }
                 }
             }
--- a/jdk/src/java.base/share/native/libjava/Bits.c	Wed Jul 05 21:22:48 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-/*
- * Copyright (c) 2002, 2010, 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.
- */
-
-/*
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jlong.h"
-#include <string.h>
-
-#define MBYTE 1048576
-
-#define GETCRITICAL_OR_RETURN(bytes, env, obj) { \
-    bytes = (*env)->GetPrimitiveArrayCritical(env, obj, NULL); \
-    if (bytes == NULL)  { \
-        if ((*env)->ExceptionOccurred(env) == NULL) \
-            JNU_ThrowInternalError(env, "Unable to get array"); \
-        return; \
-    } \
-}
-
-#define RELEASECRITICAL(bytes, env, obj, mode) { \
-    (*env)->ReleasePrimitiveArrayCritical(env, obj, bytes, mode); \
-}
-
-#define SWAPSHORT(x) ((jshort)(((x) << 8) | (((x) >> 8) & 0xff)))
-#define SWAPINT(x)   ((jint)((SWAPSHORT((jshort)(x)) << 16) | \
-                            (SWAPSHORT((jshort)((x) >> 16)) & 0xffff)))
-#define SWAPLONG(x)  ((jlong)(((jlong)SWAPINT((jint)(x)) << 32) | \
-                              ((jlong)SWAPINT((jint)((x) >> 32)) & 0xffffffff)))
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyFromShortArray(JNIEnv *env, jclass clazz, jobject src,
-                                      jlong srcPos, jlong dstAddr, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jshort *srcShort, *dstShort, *endShort;
-    jshort tmpShort;
-
-    dstShort = (jshort *)jlong_to_ptr(dstAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, src);
-
-        srcShort = (jshort *)(bytes + srcPos);
-        endShort = srcShort + (size / sizeof(jshort));
-        while (srcShort < endShort) {
-          tmpShort = *srcShort++;
-          *dstShort++ = SWAPSHORT(tmpShort);
-        }
-
-        RELEASECRITICAL(bytes, env, src, JNI_ABORT);
-
-        length -= size;
-        srcPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyToShortArray(JNIEnv *env, jclass clazz, jlong srcAddr,
-                                    jobject dst, jlong dstPos, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jshort *srcShort, *dstShort, *endShort;
-    jshort tmpShort;
-
-    srcShort = (jshort *)jlong_to_ptr(srcAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, dst);
-
-        dstShort = (jshort *)(bytes + dstPos);
-        endShort = srcShort + (size / sizeof(jshort));
-        while (srcShort < endShort) {
-            tmpShort = *srcShort++;
-            *dstShort++ = SWAPSHORT(tmpShort);
-        }
-
-        RELEASECRITICAL(bytes, env, dst, 0);
-
-        length -= size;
-        dstPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyFromIntArray(JNIEnv *env, jclass clazz, jobject src,
-                                    jlong srcPos, jlong dstAddr, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jint *srcInt, *dstInt, *endInt;
-    jint tmpInt;
-
-    dstInt = (jint *)jlong_to_ptr(dstAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, src);
-
-        srcInt = (jint *)(bytes + srcPos);
-        endInt = srcInt + (size / sizeof(jint));
-        while (srcInt < endInt) {
-            tmpInt = *srcInt++;
-            *dstInt++ = SWAPINT(tmpInt);
-        }
-
-        RELEASECRITICAL(bytes, env, src, JNI_ABORT);
-
-        length -= size;
-        srcPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyToIntArray(JNIEnv *env, jclass clazz, jlong srcAddr,
-                                  jobject dst, jlong dstPos, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jint *srcInt, *dstInt, *endInt;
-    jint tmpInt;
-
-    srcInt = (jint *)jlong_to_ptr(srcAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, dst);
-
-        dstInt = (jint *)(bytes + dstPos);
-        endInt = srcInt + (size / sizeof(jint));
-        while (srcInt < endInt) {
-            tmpInt = *srcInt++;
-            *dstInt++ = SWAPINT(tmpInt);
-        }
-
-        RELEASECRITICAL(bytes, env, dst, 0);
-
-        length -= size;
-        dstPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyFromLongArray(JNIEnv *env, jclass clazz, jobject src,
-                                     jlong srcPos, jlong dstAddr, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jlong *srcLong, *dstLong, *endLong;
-    jlong tmpLong;
-
-    dstLong = (jlong *)jlong_to_ptr(dstAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, src);
-
-        srcLong = (jlong *)(bytes + srcPos);
-        endLong = srcLong + (size / sizeof(jlong));
-        while (srcLong < endLong) {
-            tmpLong = *srcLong++;
-            *dstLong++ = SWAPLONG(tmpLong);
-        }
-
-        RELEASECRITICAL(bytes, env, src, JNI_ABORT);
-
-        length -= size;
-        srcPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyToLongArray(JNIEnv *env, jclass clazz, jlong srcAddr,
-                                   jobject dst, jlong dstPos, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jlong *srcLong, *dstLong, *endLong;
-    jlong tmpLong;
-
-    srcLong = (jlong *)jlong_to_ptr(srcAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, dst);
-
-        dstLong = (jlong *)(bytes + dstPos);
-        endLong = srcLong + (size / sizeof(jlong));
-        while (srcLong < endLong) {
-            tmpLong = *srcLong++;
-            *dstLong++ = SWAPLONG(tmpLong);
-        }
-
-        RELEASECRITICAL(bytes, env, dst, 0);
-
-        length -= size;
-        dstPos += size;
-    }
-}
--- a/jdk/src/java.base/share/native/libnet/net_util.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/native/libnet/net_util.c	Wed Jul 05 21:24:14 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
@@ -29,14 +29,21 @@
 #include "net_util.h"
 
 int IPv6_supported() ;
+int reuseport_supported() ;
 
 static int IPv6_available;
+static int REUSEPORT_available;
 
 JNIEXPORT jint JNICALL ipv6_available()
 {
     return IPv6_available ;
 }
 
+JNIEXPORT jint JNICALL reuseport_available()
+{
+    return REUSEPORT_available;
+}
+
 JNIEXPORT jint JNICALL
 DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
 {
@@ -45,7 +52,6 @@
     jmethodID mid;
     jstring s;
     jint preferIPv4Stack;
-
     if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK) {
         return JNI_EVERSION; /* JNI version not supported */
     }
@@ -64,6 +70,9 @@
        supporting socket APIs are available
     */
     IPv6_available = IPv6_supported() & (!preferIPv4Stack);
+
+    /* check if SO_REUSEPORT is supported on this platform */
+    REUSEPORT_available = reuseport_supported();
     platformInit();
     parseExclusiveBindProperty(env);
 
--- a/jdk/src/java.base/share/native/libnet/net_util.h	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/native/libnet/net_util.h	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, 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
@@ -131,6 +131,8 @@
 
 JNIEXPORT jint JNICALL ipv6_available() ;
 
+JNIEXPORT jint JNICALL reuseport_available() ;
+
 void
 NET_AllocSockaddr(struct sockaddr **him, int *len);
 
--- a/jdk/src/java.base/share/native/libzip/CRC32.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/share/native/libzip/CRC32.c	Wed Jul 05 21:24:14 2017 +0200
@@ -54,7 +54,7 @@
     return crc;
 }
 
-JNIEXPORT jint JNICALL
+jint JNICALL
 ZIP_CRC32(jint crc, const jbyte *buf, jint len)
 {
     return crc32(crc, (Bytef*)buf, len);
--- a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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,7 +45,15 @@
 
     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
-            super.setOption(name, value);
+            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+                super.setOption(name, value);
+            } else {
+               if (supportedOptions().contains(name)) {
+                   super.setOption(name, value);
+               } else {
+                   throw new UnsupportedOperationException("unsupported option");
+               }
+            }
         } else {
             if (!flowSupported()) {
                 throw new UnsupportedOperationException("unsupported option");
@@ -62,7 +70,15 @@
     @SuppressWarnings("unchecked")
     protected <T> T getOption(SocketOption<T> name) throws IOException {
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
-            return super.getOption(name);
+            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+                return super.getOption(name);
+            } else {
+                if (supportedOptions().contains(name)) {
+                    return super.getOption(name);
+                } else {
+                    throw new UnsupportedOperationException("unsupported option");
+                }
+            }
         }
         if (!flowSupported()) {
             throw new UnsupportedOperationException("unsupported option");
@@ -87,6 +103,9 @@
     }
 
     protected void socketSetOption(int opt, Object val) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
         try {
             socketSetOption0(opt, val);
         } catch (SocketException se) {
--- a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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,15 @@
 
     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
-            super.setOption(name, value);
+            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+                super.setOption(name, value);
+            } else {
+                if (supportedOptions().contains(name)) {
+                    super.setOption(name, value);
+                } else {
+                    throw new UnsupportedOperationException("unsupported option");
+                }
+            }
         } else {
             if (getSocket() == null || !flowSupported()) {
                 throw new UnsupportedOperationException("unsupported option");
@@ -76,7 +84,15 @@
     @SuppressWarnings("unchecked")
     protected <T> T getOption(SocketOption<T> name) throws IOException {
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
-            return super.getOption(name);
+            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+                return super.getOption(name);
+            } else {
+                if (supportedOptions().contains(name)) {
+                    return super.getOption(name);
+                } else {
+                    throw new UnsupportedOperationException("unsupported option");
+                }
+            }
         }
         if (getSocket() == null || !flowSupported()) {
             throw new UnsupportedOperationException("unsupported option");
@@ -101,6 +117,9 @@
     }
 
     protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
         try {
             socketSetOption0(opt, b, val);
         } catch (SocketException se) {
--- a/jdk/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java	Wed Jul 05 21:24:14 2017 +0200
@@ -85,7 +85,7 @@
                 synchronized (instance) {
                     result = getCachedJarFile(url);
                     if (result == null) {
-                        fileCache.put(URLUtil.urlNoFragString(url), local_result);
+                        fileCache.put(urlKey(url), local_result);
                         urlCache.put(local_result, url);
                         result = local_result;
                     } else {
@@ -113,13 +113,13 @@
         synchronized (instance) {
             URL urlRemoved = urlCache.remove(jarFile);
             if (urlRemoved != null)
-                fileCache.remove(URLUtil.urlNoFragString(urlRemoved));
+                fileCache.remove(urlKey(urlRemoved));
         }
     }
 
     private JarFile getCachedJarFile(URL url) {
         assert Thread.holdsLock(instance);
-        JarFile result = fileCache.get(URLUtil.urlNoFragString(url));
+        JarFile result = fileCache.get(urlKey(url));
 
         /* if the JAR file is cached, the permission will always be there */
         if (result != null) {
@@ -149,6 +149,12 @@
         return result;
     }
 
+    private String urlKey(URL url) {
+        String urlstr =  URLUtil.urlNoFragString(url);
+        if ("runtime".equals(url.getRef())) urlstr += "#runtime";
+        return urlstr;
+    }
+
     private Permission getPermission(JarFile jarFile) {
         try {
             URLConnection uc = getConnection(jarFile);
--- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Wed Jul 05 21:24:14 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
@@ -1392,6 +1392,7 @@
             }
 
         case java_net_SocketOptions_SO_REUSEADDR:
+        case java_net_SocketOptions_SO_REUSEPORT:
         case java_net_SocketOptions_SO_BROADCAST:
             {
                 jclass cls;
@@ -1769,6 +1770,9 @@
         case java_net_SocketOptions_SO_REUSEADDR:
             return createBoolean(env, optval.i);
 
+        case java_net_SocketOptions_SO_REUSEPORT:
+            return createBoolean(env, optval.i);
+
         case java_net_SocketOptions_SO_SNDBUF:
         case java_net_SocketOptions_SO_RCVBUF:
         case java_net_SocketOptions_IP_TOS:
--- a/jdk/src/java.base/unix/native/libnet/SdpSupport.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnet/SdpSupport.c	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 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
@@ -108,6 +108,11 @@
         len = sizeof(arg);
         if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0)
             setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len);
+#ifdef SO_REUSEPORT
+        len = sizeof(arg);
+        if (getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&arg, &len) == 0)
+            setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (char*)&arg, len);
+#endif
         len = sizeof(arg);
         if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0)
             setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/unix/native/libnet/SocketImpl.c	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+#include <string.h>
+
+#include "net_util.h"
+
+JNIEXPORT jboolean JNICALL
+Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
+}
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, 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
@@ -439,6 +439,25 @@
 }
 #endif /* DONT_ENABLE_IPV6 */
 
+jint reuseport_supported()
+{
+    /* Do a simple dummy call, and try to figure out from that */
+    int one = 1;
+    int rv, s;
+    s = socket(PF_INET, SOCK_STREAM, 0);
+    if (s < 0) {
+        return JNI_FALSE;
+    }
+    rv = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(one));
+    if (rv != 0) {
+        rv = JNI_FALSE;
+    } else {
+        rv = JNI_TRUE;
+    }
+    close(s);
+    return rv;
+}
+
 void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
                                                const char* hostname,
                                                int gai_error)
@@ -1014,6 +1033,7 @@
         { java_net_SocketOptions_SO_RCVBUF,             SOL_SOCKET,     SO_RCVBUF },
         { java_net_SocketOptions_SO_KEEPALIVE,          SOL_SOCKET,     SO_KEEPALIVE },
         { java_net_SocketOptions_SO_REUSEADDR,          SOL_SOCKET,     SO_REUSEADDR },
+        { java_net_SocketOptions_SO_REUSEPORT,          SOL_SOCKET,     SO_REUSEPORT },
         { java_net_SocketOptions_SO_BROADCAST,          SOL_SOCKET,     SO_BROADCAST },
         { java_net_SocketOptions_IP_TOS,                IPPROTO_IP,     IP_TOS },
         { java_net_SocketOptions_IP_MULTICAST_IF,       IPPROTO_IP,     IP_MULTICAST_IF },
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.h	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,19 @@
 #define NET_WAIT_WRITE   0x02
 #define NET_WAIT_CONNECT 0x04
 
+/* Defines SO_REUSEPORT */
+#ifndef SO_REUSEPORT
+#ifdef __linux__
+#define SO_REUSEPORT 15
+#elif __solaris__
+#define SO_REUSEPORT 0x100e
+#elif defined(AIX) || defined(MACOSX)
+#define SO_REUSEPORT 0x0200
+#else
+#define SO_REUSEPORT 0
+#endif
+#endif
+
 jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout);
 
 /************************************************************************
--- a/jdk/src/java.base/unix/native/libnio/ch/Net.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnio/ch/Net.c	Wed Jul 05 21:24:14 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
@@ -161,6 +161,12 @@
     return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
+}
+
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
     return -1;
--- a/jdk/src/java.base/unix/native/libnio/ch/nio_util.h	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnio/ch/nio_util.h	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2008, 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
@@ -36,6 +36,18 @@
   } while((_result == -1) && (errno == EINTR)); \
 } while(0)
 
+/* Defines SO_REUSEPORT */
+#ifndef SO_REUSEPORT
+#ifdef __linux__
+#define SO_REUSEPORT 15
+#elif __solaris__
+#define SO_REUSEPORT 0x100e
+#elif defined(AIX) || defined(MACOSX)
+#define SO_REUSEPORT 0x0200
+#else
+#define SO_REUSEPORT 0
+#endif
+#endif
 
 /* NIO utility procedures */
 
--- a/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -167,6 +167,11 @@
 
         int optionValue = 0;
 
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+
         switch(opt) {
             case IP_TOS :
             case SO_RCVBUF :
@@ -200,6 +205,9 @@
         }
         if (opt == SO_REUSEADDR && reuseAddressEmulated)
             return isReuseAddress;
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT)
+            throw new UnsupportedOperationException("unsupported option");
 
         int value = socketGetIntOption(nativefd, opt);
         Object returnValue = null;
--- a/jdk/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -181,6 +181,10 @@
         if (opt == SO_TIMEOUT) {  // timeout implemented through select.
             return;
         }
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
 
         int optionValue = 0;
 
@@ -224,6 +228,10 @@
             localAddress(nativefd, (InetAddressContainer)iaContainerObj);
             return 0;  // return value doesn't matter.
         }
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
 
         // SO_REUSEADDR emulated when using exclusive bind
         if (opt == SO_REUSEADDR && exclusiveBind)
--- a/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -173,10 +173,18 @@
     }
 
     public void setOption(int opt, Object val) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         impl.setOption(opt, val);
     }
 
     public Object getOption(int opt) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         return impl.getOption(opt);
     }
 
@@ -332,14 +340,27 @@
 
     void socketSetOption(int cmd, boolean on, Object value)
         throws SocketException {
+        if (cmd == SocketOptions.SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         impl.socketSetOption(cmd, on, value);
     }
 
     int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         return impl.socketGetOption(opt, iaContainerObj);
     }
 
     void socketSendUrgentData(int data) throws IOException {
         impl.socketSendUrgentData(data);
     }
+
+    static boolean isReusePortAvailable() {
+        // SO_REUSEPORT is not supported on Windows.
+        return false;
+    }
 }
--- a/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -130,6 +130,9 @@
             return socketLocalAddress(family);
         } else if (optID == SO_REUSEADDR && reuseAddressEmulated) {
             return isReuseAddress;
+        } else if (optID == SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
         } else {
             return super.getOption(optID);
         }
@@ -142,6 +145,9 @@
             // socket already bound, emulate
             reuseAddressEmulated = true;
             isReuseAddress = (Boolean)val;
+        } else if (opt == SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
         } else {
             socketNativeSetOption(opt, val);
         }
--- a/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -128,6 +128,9 @@
         } else if (opt == SO_REUSEADDR && exclusiveBind) {
             // SO_REUSEADDR emulated when using exclusive bind
             return isReuseAddress;
+        } else if (opt == SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
         } else
             return super.getOption(opt);
     }
@@ -144,6 +147,10 @@
         // SO_REUSEADDR emulated when using exclusive bind
         if (opt == SO_REUSEADDR && exclusiveBind)
             isReuseAddress = on;
+        else if (opt == SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         else
             socketNativeSetOption(opt, on, value);
     }
--- a/jdk/src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java	Wed Jul 05 21:24:14 2017 +0200
@@ -95,7 +95,7 @@
                 synchronized (instance) {
                     result = getCachedJarFile(url);
                     if (result == null) {
-                        fileCache.put(URLUtil.urlNoFragString(url), local_result);
+                        fileCache.put(urlKey(url), local_result);
                         urlCache.put(local_result, url);
                         result = local_result;
                     } else {
@@ -123,13 +123,13 @@
         synchronized (instance) {
             URL urlRemoved = urlCache.remove(jarFile);
             if (urlRemoved != null)
-                fileCache.remove(URLUtil.urlNoFragString(urlRemoved));
+                fileCache.remove(urlKey(urlRemoved));
         }
     }
 
     private JarFile getCachedJarFile(URL url) {
         assert Thread.holdsLock(instance);
-        JarFile result = fileCache.get(URLUtil.urlNoFragString(url));
+        JarFile result = fileCache.get(urlKey(url));
 
         /* if the JAR file is cached, the permission will always be there */
         if (result != null) {
@@ -159,6 +159,12 @@
         return result;
     }
 
+    private String urlKey(URL url) {
+        String urlstr =  URLUtil.urlNoFragString(url);
+        if ("runtime".equals(url.getRef())) urlstr += "#runtime";
+        return urlstr;
+    }
+
     private Permission getPermission(JarFile jarFile) {
         try {
             URLConnection uc = getConnection(jarFile);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/windows/native/libnet/SocketImpl.c	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+
+JNIEXPORT jboolean JNICALL
+Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    // SO_REUSEPORT is not supported on Windows
+    return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    // SO_REUSEPORT is not supported on Windows
+    return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    // SO_REUSEPORT is not supported on Windows
+    return JNI_FALSE;
+}
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, 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
@@ -242,6 +242,11 @@
     return JNI_TRUE;
 }
 
+jint reuseport_supported()
+{
+    /* SO_REUSEPORT is not supported onn Windows */
+    return JNI_FALSE;
+}
 /*
  * Return the default TOS value
  */
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.h	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.h	Wed Jul 05 21:24:14 2017 +0200
@@ -54,6 +54,9 @@
 
 #else
 
+/*SO_REUSEPORT is not supported on Windows, define it to 0*/
+#define SO_REUSEPORT 0
+
 /* Retain this code a little longer to support building in
  * old environments.  _MSC_VER is defined as:
  *     1200 for MSVC++ 6.0
@@ -353,3 +356,4 @@
 
 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0_XP
 (JNIEnv *env, jclass cls, jstring name, jint index);
+
--- a/jdk/src/java.base/windows/native/libnio/ch/Net.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/java.base/windows/native/libnio/ch/Net.c	Wed Jul 05 21:24:14 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
@@ -93,6 +93,13 @@
     return ipv6_available() ? JNI_TRUE : JNI_FALSE;
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    // SO_REUSEPORT is not supported on Windows
+    return JNI_FALSE;
+}
+
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
     return 1;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.nio.channels.SelectableChannel;
+
+/**
+ * Event handling interface from HttpClientImpl's selector.
+ *
+ * <p> If blockingChannel is true, then the channel will be put in blocking
+ * mode prior to handle() being called. If false, then it remains non-blocking.
+ */
+abstract class AsyncEvent {
+
+    /**
+     * Implement this if channel should be made blocking before calling handle()
+     */
+    public interface Blocking { }
+
+    /**
+     * Implement this if channel should remain non-blocking before calling handle()
+     */
+    public interface NonBlocking { }
+
+    /** Returns the channel */
+    public abstract SelectableChannel channel();
+
+    /** Returns the selector interest op flags OR'd */
+    public abstract int interestOps();
+
+    /** Called when event occurs */
+    public abstract void handle();
+
+    /** Called when selector is shutting down. Abort all exchanges. */
+    public abstract void abort();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,306 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import static java.net.Authenticator.RequestorType.PROXY;
+import static java.net.Authenticator.RequestorType.SERVER;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.InetSocketAddress;
+import java.net.URISyntaxException;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.LinkedList;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
+/**
+ * Implementation of Http Basic authentication.
+ */
+class AuthenticationFilter implements HeaderFilter {
+
+    static private final Base64.Encoder encoder = Base64.getEncoder();
+
+    static final int DEFAULT_RETRY_LIMIT = 3;
+
+    static final int retry_limit = Utils.getIntegerNetProperty(
+            "sun.net.httpclient.auth.retrylimit", DEFAULT_RETRY_LIMIT);
+
+    static final int UNAUTHORIZED = 401;
+    static final int PROXY_UNAUTHORIZED = 407;
+
+    private PasswordAuthentication getCredentials(String header,
+                                                  boolean proxy,
+                                                  HttpRequestImpl req)
+        throws IOException
+    {
+        HttpClientImpl client = req.client();
+        java.net.Authenticator auth =
+                client.authenticator()
+                      .orElseThrow(() -> new IOException("No authenticator set"));
+        URI uri = req.uri();
+        HeaderParser parser = new HeaderParser(header);
+        String authscheme = parser.findKey(0);
+
+        String realm = parser.findValue("realm");
+        java.net.Authenticator.RequestorType rtype = proxy ? PROXY : SERVER;
+
+        // needs to be instance method in Authenticator
+        return auth.requestPasswordAuthenticationInstance(uri.getHost(),
+                                                          null,
+                                                          uri.getPort(),
+                                                          uri.getScheme(),
+                                                          realm,
+                                                          authscheme,
+                                                          uri.toURL(),
+                                                          rtype
+        );
+    }
+
+    private URI getProxyURI(HttpRequestImpl r) {
+        InetSocketAddress proxy = r.proxy();
+        if (proxy == null) {
+            return null;
+        }
+
+        // our own private scheme for proxy URLs
+        // eg. proxy.http://host:port/
+        String scheme = "proxy." + r.uri().getScheme();
+        try {
+            return new URI(scheme,
+                           null,
+                           proxy.getHostString(),
+                           proxy.getPort(),
+                           null,
+                           null,
+                           null);
+        } catch (URISyntaxException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    @Override
+    public void request(HttpRequestImpl r) throws IOException {
+        // use preemptive authentication if an entry exists.
+        Cache cache = getCache(r);
+
+        // Proxy
+        if (r.exchange.proxyauth == null) {
+            URI proxyURI = getProxyURI(r);
+            if (proxyURI != null) {
+                CacheEntry ca = cache.get(proxyURI, true);
+                if (ca != null) {
+                    r.exchange.proxyauth = new AuthInfo(true, ca.scheme, null, ca);
+                    addBasicCredentials(r, true, ca.value);
+                }
+            }
+        }
+
+        // Server
+        if (r.exchange.serverauth == null) {
+            CacheEntry ca = cache.get(r.uri(), false);
+            if (ca != null) {
+                r.exchange.serverauth = new AuthInfo(true, ca.scheme, null, ca);
+                addBasicCredentials(r, false, ca.value);
+            }
+        }
+    }
+
+    // TODO: refactor into per auth scheme class
+    static private void addBasicCredentials(HttpRequestImpl r,
+                                            boolean proxy,
+                                            PasswordAuthentication pw) {
+        String hdrname = proxy ? "Proxy-Authorization" : "Authorization";
+        StringBuilder sb = new StringBuilder(128);
+        sb.append(pw.getUserName()).append(':').append(pw.getPassword());
+        String s = encoder.encodeToString(sb.toString().getBytes(ISO_8859_1));
+        String value = "Basic " + s;
+        r.setSystemHeader(hdrname, value);
+    }
+
+    // Information attached to a HttpRequestImpl relating to authentication
+    static class AuthInfo {
+        final boolean fromcache;
+        final String scheme;
+        int retries;
+        PasswordAuthentication credentials; // used in request
+        CacheEntry cacheEntry; // if used
+
+        AuthInfo(boolean fromcache,
+                 String scheme,
+                 PasswordAuthentication credentials) {
+            this.fromcache = fromcache;
+            this.scheme = scheme;
+            this.credentials = credentials;
+            this.retries = 1;
+        }
+
+        AuthInfo(boolean fromcache,
+                 String scheme,
+                 PasswordAuthentication credentials,
+                 CacheEntry ca) {
+            this(fromcache, scheme, credentials);
+            assert credentials == null || (ca != null && ca.value == null);
+            cacheEntry = ca;
+        }
+    }
+
+    @Override
+    public HttpRequestImpl response(HttpResponseImpl r) throws IOException {
+        Cache cache = getCache(r.request);
+        int status = r.statusCode();
+        HttpHeaders hdrs = r.headers();
+        HttpRequestImpl req = r.request();
+
+        if (status != UNAUTHORIZED && status != PROXY_UNAUTHORIZED) {
+            // check if any authentication succeeded for first time
+            if (req.exchange.serverauth != null && !req.exchange.serverauth.fromcache) {
+                AuthInfo au = req.exchange.serverauth;
+                cache.store(au.scheme, req.uri(), false, au.credentials);
+            }
+            if (req.exchange.proxyauth != null && !req.exchange.proxyauth.fromcache) {
+                AuthInfo au = req.exchange.proxyauth;
+                cache.store(au.scheme, req.uri(), false, au.credentials);
+            }
+            return null;
+        }
+
+        boolean proxy = status == PROXY_UNAUTHORIZED;
+        String authname = proxy ? "Proxy-Authentication" : "WWW-Authenticate";
+        String authval = hdrs.firstValue(authname).orElseThrow(() -> {
+            return new IOException("Invalid auth header");
+        });
+        HeaderParser parser = new HeaderParser(authval);
+        String scheme = parser.findKey(0);
+
+        // TODO: Need to generalise from Basic only. Delegate to a provider class etc.
+
+        if (!scheme.equalsIgnoreCase("Basic")) {
+            return null;   // error gets returned to app
+        }
+
+        String realm = parser.findValue("realm");
+        AuthInfo au = proxy ? req.exchange.proxyauth : req.exchange.serverauth;
+        if (au == null) {
+            PasswordAuthentication pw = getCredentials(authval, proxy, req);
+            if (pw == null) {
+                throw new IOException("No credentials provided");
+            }
+            // No authentication in request. Get credentials from user
+            au = new AuthInfo(false, "Basic", pw);
+            if (proxy)
+                req.exchange.proxyauth = au;
+            else
+                req.exchange.serverauth = au;
+            addBasicCredentials(req, proxy, pw);
+            return req;
+        } else if (au.retries > retry_limit) {
+            throw new IOException("too many authentication attempts");
+        } else {
+            // we sent credentials, but they were rejected
+            if (au.fromcache) {
+                cache.remove(au.cacheEntry);
+            }
+            // try again
+            au.credentials = getCredentials(authval, proxy, req);
+            addBasicCredentials(req, proxy, au.credentials);
+            au.retries++;
+            return req;
+        }
+    }
+
+    static final HashMap<HttpClientImpl,Cache> caches = new HashMap<>();
+
+    static synchronized Cache getCache(HttpRequestImpl req) {
+        HttpClientImpl client = req.client();
+        Cache c = caches.get(client);
+        if (c == null) {
+            c = new Cache();
+            caches.put(client, c);
+        }
+        return c;
+    }
+
+    static class Cache {
+        final LinkedList<CacheEntry> entries = new LinkedList<>();
+
+        synchronized CacheEntry get(URI uri, boolean proxy) {
+            for (CacheEntry entry : entries) {
+                if (entry.equalsKey(uri, proxy)) {
+                    return entry;
+                }
+            }
+            return null;
+        }
+
+        synchronized void remove(String authscheme, URI domain, boolean proxy) {
+            for (CacheEntry entry : entries) {
+                if (entry.equalsKey(domain, proxy)) {
+                    entries.remove(entry);
+                }
+            }
+        }
+
+        synchronized void remove(CacheEntry entry) {
+            entries.remove(entry);
+        }
+
+        synchronized void store(String authscheme,
+                                URI domain,
+                                boolean proxy,
+                                PasswordAuthentication value) {
+            remove(authscheme, domain, proxy);
+            entries.add(new CacheEntry(authscheme, domain, proxy, value));
+        }
+    }
+
+    static class CacheEntry {
+        final String root;
+        final String scheme;
+        final boolean proxy;
+        final PasswordAuthentication value;
+
+        CacheEntry(String authscheme,
+                   URI uri,
+                   boolean proxy,
+                   PasswordAuthentication value) {
+            this.scheme = authscheme;
+            this.root = uri.resolve(".").toString(); // remove extraneous components
+            this.proxy = proxy;
+            this.value = value;
+        }
+
+        public PasswordAuthentication value() {
+            return value;
+        }
+
+        public boolean equalsKey(URI uri, boolean proxy) {
+            if (this.proxy != proxy) {
+                return false;
+            }
+            String other = uri.toString();
+            return other.startsWith(root);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Implemented by buffer pools.
+ */
+interface BufferHandler {
+
+    ByteBuffer getBuffer();
+
+    void returnBuffer(ByteBuffer buffer);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,272 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.Objects;
+
+/**
+ * Http 1.1 connection pool.
+ */
+class ConnectionPool {
+
+    static final long KEEP_ALIVE = Utils.getIntegerNetProperty(
+            "sun.net.httpclient.keepalive.timeout", 1200); // seconds
+
+    // Pools of idle connections
+
+    final HashMap<CacheKey,LinkedList<HttpConnection>> plainPool;
+    final HashMap<CacheKey,LinkedList<HttpConnection>> sslPool;
+    CacheCleaner cleaner;
+
+    /**
+     * Entries in connection pool are keyed by destination address and/or
+     * proxy address:
+     * case 1: plain TCP not via proxy (destination only)
+     * case 2: plain TCP via proxy (proxy only)
+     * case 3: SSL not via proxy (destination only)
+     * case 4: SSL over tunnel (destination and proxy)
+     */
+    static class CacheKey {
+        final InetSocketAddress proxy;
+        final InetSocketAddress destination;
+
+        CacheKey(InetSocketAddress destination, InetSocketAddress proxy) {
+            this.proxy = proxy;
+            this.destination = destination;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final CacheKey other = (CacheKey) obj;
+            if (!Objects.equals(this.proxy, other.proxy)) {
+                return false;
+            }
+            if (!Objects.equals(this.destination, other.destination)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(proxy, destination);
+        }
+    }
+
+    static class ExpiryEntry {
+        final HttpConnection connection;
+        final long expiry; // absolute time in seconds of expiry time
+        ExpiryEntry(HttpConnection connection, long expiry) {
+            this.connection = connection;
+            this.expiry = expiry;
+        }
+    }
+
+    final LinkedList<ExpiryEntry> expiryList;
+
+    /**
+     * There should be one of these per HttpClient.
+     */
+    ConnectionPool() {
+        plainPool = new HashMap<>();
+        sslPool = new HashMap<>();
+        expiryList = new LinkedList<>();
+        cleaner = new CacheCleaner();
+    }
+
+    void start() {
+        cleaner.start();
+    }
+
+    static CacheKey cacheKey(InetSocketAddress destination,
+                             InetSocketAddress proxy) {
+        return new CacheKey(destination, proxy);
+    }
+
+    synchronized HttpConnection getConnection(boolean secure,
+                                              InetSocketAddress addr,
+                                              InetSocketAddress proxy) {
+        CacheKey key = new CacheKey(addr, proxy);
+        HttpConnection c = secure ? findConnection(key, sslPool)
+                                  : findConnection(key, plainPool);
+        //System.out.println ("getConnection returning: " + c);
+        return c;
+    }
+
+    /**
+     * Returns the connection to the pool.
+     *
+     * @param conn
+     */
+    synchronized void returnToPool(HttpConnection conn) {
+        if (conn instanceof PlainHttpConnection) {
+            putConnection(conn, plainPool);
+        } else {
+            putConnection(conn, sslPool);
+        }
+        addToExpiryList(conn);
+        //System.out.println("Return to pool: " + conn);
+    }
+
+    private HttpConnection
+    findConnection(CacheKey key,
+                   HashMap<CacheKey,LinkedList<HttpConnection>> pool) {
+        LinkedList<HttpConnection> l = pool.get(key);
+        if (l == null || l.size() == 0) {
+            return null;
+        } else {
+            HttpConnection c = l.removeFirst();
+            removeFromExpiryList(c);
+            return c;
+        }
+    }
+
+    /* called from cache cleaner only  */
+    private void
+    removeFromPool(HttpConnection c,
+                   HashMap<CacheKey,LinkedList<HttpConnection>> pool) {
+        //System.out.println("cacheCleaner removing: " + c);
+        LinkedList<HttpConnection> l = pool.get(c.cacheKey());
+        assert l != null;
+        boolean wasPresent = l.remove(c);
+        assert wasPresent;
+    }
+
+    private void
+    putConnection(HttpConnection c,
+                  HashMap<CacheKey,LinkedList<HttpConnection>> pool) {
+        CacheKey key = c.cacheKey();
+        LinkedList<HttpConnection> l = pool.get(key);
+        if (l == null) {
+            l = new LinkedList<>();
+            pool.put(key, l);
+        }
+        l.add(c);
+    }
+
+    // only runs while entries exist in cache
+
+    class CacheCleaner extends Thread {
+
+        volatile boolean stopping;
+
+        CacheCleaner() {
+            super(null, null, "HTTP-Cache-cleaner", 0, false);
+            setDaemon(true);
+        }
+
+        synchronized boolean stopping() {
+            return stopping;
+        }
+
+        synchronized void stopCleaner() {
+            stopping = true;
+        }
+
+        @Override
+        public void run() {
+            while (!stopping()) {
+                try {
+                    Thread.sleep(3000);
+                } catch (InterruptedException e) {}
+                cleanCache();
+            }
+        }
+    }
+
+    synchronized void removeFromExpiryList(HttpConnection c) {
+        if (c == null) {
+            return;
+        }
+        ListIterator<ExpiryEntry> li = expiryList.listIterator();
+        while (li.hasNext()) {
+            ExpiryEntry e = li.next();
+            if (e.connection.equals(c)) {
+                li.remove();
+                return;
+            }
+        }
+        if (expiryList.isEmpty()) {
+            cleaner.stopCleaner();
+        }
+    }
+
+    private void cleanCache() {
+        long now = System.currentTimeMillis() / 1000;
+        LinkedList<HttpConnection> closelist = new LinkedList<>();
+
+        synchronized (this) {
+            ListIterator<ExpiryEntry> li = expiryList.listIterator();
+            while (li.hasNext()) {
+                ExpiryEntry entry = li.next();
+                if (entry.expiry <= now) {
+                    li.remove();
+                    HttpConnection c = entry.connection;
+                    closelist.add(c);
+                    if (c instanceof PlainHttpConnection) {
+                        removeFromPool(c, plainPool);
+                    } else {
+                        removeFromPool(c, sslPool);
+                    }
+                }
+            }
+        }
+        for (HttpConnection c : closelist) {
+            //System.out.println ("KAC: closing " + c);
+            c.close();
+        }
+    }
+
+    private synchronized void addToExpiryList(HttpConnection conn) {
+        long now = System.currentTimeMillis() / 1000;
+        long then = now + KEEP_ALIVE;
+
+        if (expiryList.isEmpty())
+            cleaner = new CacheCleaner();
+
+        ListIterator<ExpiryEntry> li = expiryList.listIterator();
+        while (li.hasNext()) {
+            ExpiryEntry entry = li.next();
+
+            if (then > entry.expiry) {
+                li.previous();
+                // insert here
+                li.add(new ExpiryEntry(conn, then));
+                return;
+            }
+        }
+        // first element of list
+        expiryList.add(new ExpiryEntry(conn, then));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/CookieFilter.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,66 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.net.CookieManager;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+class CookieFilter implements HeaderFilter {
+
+    final HttpClientImpl client;
+    final CookieManager cookieMan;
+
+    CookieFilter(HttpClientImpl client) {
+        this.client = client;
+        this.cookieMan = client.cookieManager().orElseThrow(
+                () -> new IllegalArgumentException("no cookie manager"));
+    }
+
+    @Override
+    public void request(HttpRequestImpl r) throws IOException {
+        Map<String,List<String>> userheaders, cookies;
+        userheaders = r.getUserHeaders().directMap();
+        cookies = cookieMan.get(r.uri(), userheaders);
+        // add the returned cookies
+        HttpHeadersImpl systemHeaders = r.getSystemHeaders();
+        Set<String> keys = cookies.keySet();
+        for (String hdrname : keys) {
+            List<String> vals = cookies.get(hdrname);
+            for (String val : vals) {
+                systemHeaders.addHeader(hdrname, val);
+            }
+        }
+    }
+
+    @Override
+    public HttpRequestImpl response(HttpResponseImpl r) throws IOException {
+        HttpHeaders hdrs = r.headers();
+        cookieMan.put(r.uri(), hdrs.map());
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,419 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.InetSocketAddress;
+import java.net.SocketPermission;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLPermission;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * One request/response exchange (handles 100/101 intermediate response also).
+ * depth field used to track number of times a new request is being sent
+ * for a given API request. If limit exceeded exception is thrown.
+ *
+ * Security check is performed here:
+ * - uses AccessControlContext captured at API level
+ * - checks for appropriate URLPermission for request
+ * - if permission allowed, grants equivalent SocketPermission to call
+ * - in case of direct HTTP proxy, checks additionally for access to proxy
+ *    (CONNECT proxying uses its own Exchange, so check done there)
+ *
+ */
+class Exchange {
+
+    final HttpRequestImpl request;
+    final HttpClientImpl client;
+    ExchangeImpl exchImpl;
+    HttpResponseImpl response;
+    final List<SocketPermission> permissions = new LinkedList<>();
+    AccessControlContext acc;
+    boolean upgrading; // to HTTP/2
+
+    Exchange(HttpRequestImpl request) {
+        this.request = request;
+        this.upgrading = false;
+        this.client = request.client();
+    }
+
+    /* If different AccessControlContext to be used  */
+    Exchange(HttpRequestImpl request, AccessControlContext acc) {
+        this.request = request;
+        this.acc = acc;
+        this.upgrading = false;
+        this.client = request.client();
+    }
+
+    public HttpRequestImpl request() {
+        return request;
+    }
+
+    public HttpResponseImpl response() throws IOException, InterruptedException {
+        response = responseImpl(null);
+        return response;
+    }
+
+    public void cancel() {
+        if (exchImpl != null)
+            exchImpl.cancel();
+    }
+
+    public void h2Upgrade() {
+        upgrading = true;
+        request.setH2Upgrade();
+    }
+
+    static final SocketPermission[] SOCKET_ARRAY = new SocketPermission[0];
+
+    HttpResponseImpl responseImpl(HttpConnection connection)
+        throws IOException, InterruptedException
+    {
+        if (acc == null) {
+            acc = request.getAccessControlContext();
+        }
+        SecurityException e = securityCheck(acc);
+        if (e != null)
+            throw e;
+
+        if (permissions.size() > 0) {
+            try {
+                return AccessController.doPrivileged(
+                        (PrivilegedExceptionAction<HttpResponseImpl>)() ->
+                             responseImpl0(connection),
+                        null,
+                        permissions.toArray(SOCKET_ARRAY));
+            } catch (Throwable ee) {
+                if (ee instanceof PrivilegedActionException) {
+                    ee = ee.getCause();
+                }
+                if (ee instanceof IOException)
+                    throw (IOException)ee;
+                else
+                    throw new RuntimeException(ee); // TODO: fix
+            }
+        } else {
+            return responseImpl0(connection);
+        }
+    }
+
+    HttpResponseImpl responseImpl0(HttpConnection connection)
+        throws IOException, InterruptedException
+    {
+        exchImpl = ExchangeImpl.get(this, connection);
+        if (request.expectContinue()) {
+            request.addSystemHeader("Expect", "100-Continue");
+            exchImpl.sendHeadersOnly();
+            HttpResponseImpl resp = exchImpl.getResponse();
+            logResponse(resp);
+            if (resp.statusCode() != 100) {
+                return resp;
+            }
+            exchImpl.sendBody();
+            return exchImpl.getResponse();
+        } else {
+            exchImpl.sendRequest();
+            HttpResponseImpl resp = exchImpl.getResponse();
+            logResponse(resp);
+            return checkForUpgrade(resp, exchImpl);
+        }
+    }
+
+    // Completed HttpResponse will be null if response succeeded
+    // will be a non null responseAsync if expect continue returns an error
+
+    public CompletableFuture<HttpResponseImpl> responseAsync(Void v) {
+        return responseAsyncImpl(null);
+    }
+
+    CompletableFuture<HttpResponseImpl> responseAsyncImpl(HttpConnection connection) {
+        if (acc == null) {
+            acc = request.getAccessControlContext();
+        }
+        SecurityException e = securityCheck(acc);
+        if (e != null) {
+            CompletableFuture<HttpResponseImpl> cf = new CompletableFuture<>();
+            cf.completeExceptionally(e);
+            return cf;
+        }
+        if (permissions.size() > 0) {
+            return AccessController.doPrivileged(
+                    (PrivilegedAction<CompletableFuture<HttpResponseImpl>>)() ->
+                        responseAsyncImpl0(connection),
+                    null,
+                    permissions.toArray(SOCKET_ARRAY));
+        } else {
+            return responseAsyncImpl0(connection);
+        }
+    }
+
+    CompletableFuture<HttpResponseImpl> responseAsyncImpl0(HttpConnection connection) {
+        try {
+            exchImpl = ExchangeImpl.get(this, connection);
+        } catch (IOException | InterruptedException e) {
+            CompletableFuture<HttpResponseImpl> cf = new CompletableFuture<>();
+            cf.completeExceptionally(e);
+            return cf;
+        }
+        if (request.expectContinue()) {
+            request.addSystemHeader("Expect", "100-Continue");
+            return exchImpl.sendHeadersAsync()
+                    .thenCompose(exchImpl::getResponseAsync)
+                    .thenCompose((HttpResponseImpl r1) -> {
+                        int rcode = r1.statusCode();
+                        CompletableFuture<HttpResponseImpl> cf =
+                                checkForUpgradeAsync(r1, exchImpl);
+                        if (cf != null)
+                            return cf;
+                        if (rcode == 100) {
+                            return exchImpl.sendBodyAsync()
+                                .thenCompose(exchImpl::getResponseAsync)
+                                .thenApply((r) -> {
+                                    logResponse(r);
+                                    return r;
+                                });
+                        } else {
+                            Exchange.this.response = r1;
+                            logResponse(r1);
+                            return CompletableFuture.completedFuture(r1);
+                        }
+                    });
+        } else {
+            return exchImpl
+                .sendHeadersAsync()
+                .thenCompose((Void v) -> {
+                    // send body and get response at same time
+                    exchImpl.sendBodyAsync();
+                    return exchImpl.getResponseAsync(null);
+                })
+                    .thenCompose((HttpResponseImpl r1) -> {
+                        int rcode = r1.statusCode();
+                        CompletableFuture<HttpResponseImpl> cf =
+                                checkForUpgradeAsync(r1, exchImpl);
+                        if (cf != null) {
+                            return cf;
+                        } else {
+                            Exchange.this.response = r1;
+                            logResponse(r1);
+                            return CompletableFuture.completedFuture(r1);
+                        }
+                    })
+                .thenApply((HttpResponseImpl response) -> {
+                    this.response = response;
+                    logResponse(response);
+                    return response;
+                });
+        }
+    }
+
+    // if this response was received in reply to an upgrade
+    // then create the Http2Connection from the HttpConnection
+    // initialize it and wait for the real response on a newly created Stream
+
+    private CompletableFuture<HttpResponseImpl>
+    checkForUpgradeAsync(HttpResponseImpl resp,
+                         ExchangeImpl ex) {
+        int rcode = resp.statusCode();
+        if (upgrading && (rcode == 101)) {
+            Http1Exchange e = (Http1Exchange)ex;
+            // check for 101 switching protocols
+            return e.responseBodyAsync(HttpResponse.ignoreBody())
+                .thenCompose((Void v) ->
+                     Http2Connection.createAsync(e.connection(),
+                                                 client.client2(),
+                                                 this)
+                        .thenCompose((Http2Connection c) -> {
+                            Stream s = c.getStream(1);
+                            exchImpl = s;
+                            c.putConnection();
+                            return s.getResponseAsync(null);
+                        })
+                );
+        }
+        return CompletableFuture.completedFuture(resp);
+    }
+
+    private HttpResponseImpl checkForUpgrade(HttpResponseImpl resp,
+                                             ExchangeImpl ex)
+        throws IOException, InterruptedException
+    {
+        int rcode = resp.statusCode();
+        if (upgrading && (rcode == 101)) {
+            Http1Exchange e = (Http1Exchange) ex;
+            // must get connection from Http1Exchange
+            e.responseBody(HttpResponse.ignoreBody(), false);
+            Http2Connection h2con = new Http2Connection(e.connection(),
+                                                        client.client2(),
+                                                        this);
+            h2con.putConnection();
+            Stream s = h2con.getStream(1);
+            exchImpl = s;
+            return s.getResponse();
+        }
+        return resp;
+    }
+
+
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor) {
+        try {
+            return exchImpl.responseBody(processor);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+
+    private void logResponse(HttpResponseImpl r) {
+        if (!Log.requests())
+            return;
+        StringBuilder sb = new StringBuilder();
+        String method = r.request().method();
+        URI uri = r.uri();
+        String uristring = uri == null ? "" : uri.toString();
+        sb.append('(')
+          .append(method)
+          .append(" ")
+          .append(uristring)
+          .append(") ")
+          .append(Integer.toString(r.statusCode()));
+        Log.logResponse(sb.toString());
+    }
+
+    <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+        return exchImpl.responseBodyAsync(processor);
+    }
+
+    private URI getURIForSecurityCheck() {
+        URI u;
+        String method = request.method();
+        InetSocketAddress authority = request.authority();
+        URI uri = request.uri();
+
+        // CONNECT should be restricted at API level
+        if (method.equalsIgnoreCase("CONNECT")) {
+            try {
+                u = new URI("socket",
+                             null,
+                             authority.getHostString(),
+                             authority.getPort(),
+                             null,
+                             null,
+                             null);
+            } catch (URISyntaxException e) {
+                throw new InternalError(e); // shouldn't happen
+            }
+        } else {
+            u = uri;
+        }
+        return u;
+    }
+
+    /**
+     * Do the security check and return any exception.
+     * Return null if no check needed or passes.
+     *
+     * Also adds any generated permissions to the "permissions" list.
+     */
+    private SecurityException securityCheck(AccessControlContext acc) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            return null;
+        }
+
+        String method = request.method();
+        HttpHeadersImpl userHeaders = request.getUserHeaders();
+        URI u = getURIForSecurityCheck();
+        URLPermission p = Utils.getPermission(u, method, userHeaders.directMap());
+
+        try {
+            assert acc != null;
+            sm.checkPermission(p, acc);
+            permissions.add(getSocketPermissionFor(u));
+        } catch (SecurityException e) {
+            return e;
+        }
+        InetSocketAddress proxy = request.proxy();
+        if (proxy != null) {
+            // may need additional check
+            if (!method.equals("CONNECT")) {
+                // a direct http proxy. Need to check access to proxy
+                try {
+                    u = new URI("socket", null, proxy.getHostString(),
+                        proxy.getPort(), null, null, null);
+                } catch (URISyntaxException e) {
+                    throw new InternalError(e); // shouldn't happen
+                }
+                p = new URLPermission(u.toString(), "CONNECT");
+                try {
+                    sm.checkPermission(p, acc);
+                } catch (SecurityException e) {
+                    permissions.clear();
+                    return e;
+                }
+                String sockperm = proxy.getHostString() +
+                        ":" + Integer.toString(proxy.getPort());
+
+                permissions.add(new SocketPermission(sockperm, "connect,resolve"));
+            }
+        }
+        return null;
+    }
+
+    private static SocketPermission getSocketPermissionFor(URI url) {
+        if (System.getSecurityManager() == null)
+            return null;
+
+        StringBuilder sb = new StringBuilder();
+        String host = url.getHost();
+        sb.append(host);
+        int port = url.getPort();
+        if (port == -1) {
+            String scheme = url.getScheme();
+            if ("http".equals(scheme)) {
+                sb.append(":80");
+            } else { // scheme must be https
+                sb.append(":443");
+            }
+        } else {
+            sb.append(':')
+              .append(Integer.toString(port));
+        }
+        String target = sb.toString();
+        return new SocketPermission(target, "connect");
+    }
+
+    AccessControlContext getAccessControlContext() {
+        return acc;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ExchangeImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,133 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+import static java.net.http.HttpClient.Version.HTTP_1_1;
+
+/**
+ * Splits request so that headers and body can be sent separately with optional
+ * (multiple) responses in between (e.g. 100 Continue). Also request and
+ * response always sent/received in different calls.
+ *
+ * Synchronous and asynchronous versions of each method are provided.
+ *
+ * Separate implementations of this class exist for HTTP/1.1 and HTTP/2
+ *      Http1Exchange   (HTTP/1.1)
+ *      Stream          (HTTP/2)
+ *
+ * These implementation classes are where work is allocated to threads.
+ */
+abstract class ExchangeImpl {
+
+    final Exchange exchange;
+
+    ExchangeImpl(Exchange e) {
+        this.exchange = e;
+    }
+
+    /**
+     * Initiates a new exchange and assigns it to a connection if one exists
+     * already. connection usually null.
+     */
+    static ExchangeImpl get(Exchange exchange, HttpConnection connection)
+        throws IOException, InterruptedException
+    {
+        HttpRequestImpl req = exchange.request();
+        if (req.version() == HTTP_1_1) {
+            return new Http1Exchange(exchange, connection);
+        } else {
+            Http2ClientImpl c2 = exchange.request().client().client2(); // TODO: improve
+            HttpRequestImpl request = exchange.request();
+            Http2Connection c = c2.getConnectionFor(request);
+            if (c == null) {
+                // no existing connection. Send request with HTTP 1 and then
+                // upgrade if successful
+                ExchangeImpl ex = new Http1Exchange(exchange, connection);
+                exchange.h2Upgrade();
+                return ex;
+            }
+            return c.createStream(exchange);
+        }
+    }
+
+    /* The following methods have separate HTTP/1.1 and HTTP/2 implementations */
+
+    /**
+     * Sends the request headers only. May block until all sent.
+     */
+    abstract void sendHeadersOnly() throws IOException, InterruptedException;
+
+    /**
+     * Gets response headers by blocking if necessary. This may be an
+     * intermediate response (like 101) or a final response 200 etc.
+     */
+    abstract HttpResponseImpl getResponse() throws IOException;
+
+    /**
+     * Sends a request body after request headers.
+     */
+    abstract void sendBody() throws IOException, InterruptedException;
+
+    /**
+     * Sends the entire request (headers and body) blocking.
+     */
+    abstract void sendRequest() throws IOException, InterruptedException;
+
+    /**
+     * Asynchronous version of sendHeaders().
+     */
+    abstract CompletableFuture<Void> sendHeadersAsync();
+
+    /**
+     * Asynchronous version of getResponse().  Requires void parameter for
+     * CompletableFuture chaining.
+     */
+    abstract CompletableFuture<HttpResponseImpl> getResponseAsync(Void v);
+
+    /**
+     * Asynchronous version of sendBody().
+     */
+    abstract CompletableFuture<Void> sendBodyAsync();
+
+    /**
+     * Cancels a request.  Not currently exposed through API.
+     */
+    abstract void cancel();
+
+    /**
+     * Asynchronous version of sendRequest().
+     */
+    abstract CompletableFuture<Void> sendRequestAsync();
+
+    abstract <T> T responseBody(HttpResponse.BodyProcessor<T> processor)
+        throws IOException;
+
+    /**
+     * Asynchronous version of responseBody().
+     */
+    abstract <T> CompletableFuture<T>
+    responseBodyAsync(HttpResponse.BodyProcessor<T> processor);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ExecutorWrapper.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,100 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
+
+/**
+ * Wraps the supplied user ExecutorService.
+ *
+ * 1) when a Security manager set, the correct access control context
+ *    is used to execute task
+ *
+ * 2) memory fence implemented
+ */
+class ExecutorWrapper {
+
+    final ExecutorService userExecutor; // the actual executor service used
+    final Executor executor;
+
+    public static ExecutorWrapper wrap(ExecutorService userExecutor) {
+        return new ExecutorWrapper(userExecutor);
+    }
+
+    /**
+     * Returns a dummy ExecutorWrapper which uses the calling thread
+     */
+    public static ExecutorWrapper callingThread() {
+        return new ExecutorWrapper();
+    }
+
+    private ExecutorWrapper(ExecutorService userExecutor) {
+        // used for executing in calling thread
+        this.userExecutor = userExecutor;
+        this.executor = userExecutor;
+    }
+
+    private ExecutorWrapper() {
+        this.userExecutor = null;
+        this.executor = (Runnable command) -> {
+            command.run();
+        };
+    }
+
+    public ExecutorService userExecutor() {
+        return userExecutor;
+    }
+
+    public synchronized void synchronize() {}
+
+    public void execute(Runnable r, Supplier<AccessControlContext> ctxSupplier) {
+        synchronize();
+        Runnable r1 = () -> {
+            try {
+                r.run();
+            } catch (Throwable t) {
+                Log.logError(t);
+            }
+        };
+
+        if (ctxSupplier != null && System.getSecurityManager() != null) {
+            AccessControlContext acc = ctxSupplier.get();
+            if (acc == null) {
+                throw new InternalError();
+            }
+            AccessController.doPrivilegedWithCombiner(
+                (PrivilegedAction<Void>)() -> {
+                    executor.execute(r1); // all throwables must be caught
+                    return null;
+                }, acc);
+        } else {
+            executor.execute(r1); // all throwables must be caught
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/FilterFactory.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.util.LinkedList;
+import java.util.List;
+
+class FilterFactory {
+
+    final LinkedList<Class<? extends HeaderFilter>> filterClasses = new LinkedList<>();
+
+    public void addFilter(Class<? extends HeaderFilter> type) {
+        filterClasses.add(type);
+    }
+
+    List<HeaderFilter> getFilterChain() {
+        List<HeaderFilter> l = new LinkedList<>();
+        for (Class<? extends HeaderFilter> clazz : filterClasses) {
+            try {
+                l.add(clazz.newInstance());
+            } catch (ReflectiveOperationException e) {
+                throw new InternalError(e);
+            }
+        }
+        return l;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFilter.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+
+/**
+ * A header filter that can examine or modify, typically system headers for
+ * requests before they are sent, and responses before they are returned to the
+ * user. Some ability to resend requests is provided.
+ *
+ */
+interface HeaderFilter {
+
+    void request(HttpRequestImpl r) throws IOException;
+
+    /**
+     * Returns null if response ok to be given to user.  Non null is a request
+     * that must be resent and its response given to user. If impl throws an
+     * exception that is returned to user instead.
+     */
+    HttpRequestImpl response(HttpResponseImpl r) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderParser.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,245 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+
+/* This is useful for the nightmare of parsing multi-part HTTP/RFC822 headers
+ * sensibly:
+ * From a String like: 'timeout=15, max=5'
+ * create an array of Strings:
+ * { {"timeout", "15"},
+ *   {"max", "5"}
+ * }
+ * From one like: 'Basic Realm="FuzzFace" Foo="Biz Bar Baz"'
+ * create one like (no quotes in literal):
+ * { {"basic", null},
+ *   {"realm", "FuzzFace"}
+ *   {"foo", "Biz Bar Baz"}
+ * }
+ * keys are converted to lower case, vals are left as is....
+ */
+class HeaderParser {
+
+    /* table of key/val pairs */
+    String raw;
+    String[][] tab;
+    int nkeys;
+    int asize = 10; // initial size of array is 10
+
+    public HeaderParser(String raw) {
+        this.raw = raw;
+        tab = new String[asize][2];
+        parse();
+    }
+
+    private HeaderParser () { }
+
+    /**
+     * Creates a new HeaderParser from this, whose keys (and corresponding
+     * values) range from "start" to "end-1"
+     */
+    public HeaderParser subsequence(int start, int end) {
+        if (start == 0 && end == nkeys) {
+            return this;
+        }
+        if (start < 0 || start >= end || end > nkeys)
+            throw new IllegalArgumentException("invalid start or end");
+        HeaderParser n = new HeaderParser();
+        n.tab = new String [asize][2];
+        n.asize = asize;
+        System.arraycopy (tab, start, n.tab, 0, (end-start));
+        n.nkeys= (end-start);
+        return n;
+    }
+
+    private void parse() {
+
+        if (raw != null) {
+            raw = raw.trim();
+            char[] ca = raw.toCharArray();
+            int beg = 0, end = 0, i = 0;
+            boolean inKey = true;
+            boolean inQuote = false;
+            int len = ca.length;
+            while (end < len) {
+                char c = ca[end];
+                if ((c == '=') && !inQuote) { // end of a key
+                    tab[i][0] = new String(ca, beg, end-beg).toLowerCase(Locale.US);
+                    inKey = false;
+                    end++;
+                    beg = end;
+                } else if (c == '\"') {
+                    if (inQuote) {
+                        tab[i++][1]= new String(ca, beg, end-beg);
+                        inQuote=false;
+                        do {
+                            end++;
+                        } while (end < len && (ca[end] == ' ' || ca[end] == ','));
+                        inKey=true;
+                        beg=end;
+                    } else {
+                        inQuote=true;
+                        end++;
+                        beg=end;
+                    }
+                } else if (c == ' ' || c == ',') { // end key/val, of whatever we're in
+                    if (inQuote) {
+                        end++;
+                        continue;
+                    } else if (inKey) {
+                        tab[i++][0] = (new String(ca, beg, end-beg)).toLowerCase(Locale.US);
+                    } else {
+                        tab[i++][1] = (new String(ca, beg, end-beg));
+                    }
+                    while (end < len && (ca[end] == ' ' || ca[end] == ',')) {
+                        end++;
+                    }
+                    inKey = true;
+                    beg = end;
+                } else {
+                    end++;
+                }
+                if (i == asize) {
+                    asize = asize * 2;
+                    String[][] ntab = new String[asize][2];
+                    System.arraycopy (tab, 0, ntab, 0, tab.length);
+                    tab = ntab;
+                }
+            }
+            // get last key/val, if any
+            if (--end > beg) {
+                if (!inKey) {
+                    if (ca[end] == '\"') {
+                        tab[i++][1] = (new String(ca, beg, end-beg));
+                    } else {
+                        tab[i++][1] = (new String(ca, beg, end-beg+1));
+                    }
+                } else {
+                    tab[i++][0] = (new String(ca, beg, end-beg+1)).toLowerCase();
+                }
+            } else if (end == beg) {
+                if (!inKey) {
+                    if (ca[end] == '\"') {
+                        tab[i++][1] = String.valueOf(ca[end-1]);
+                    } else {
+                        tab[i++][1] = String.valueOf(ca[end]);
+                    }
+                } else {
+                    tab[i++][0] = String.valueOf(ca[end]).toLowerCase();
+                }
+            }
+            nkeys=i;
+        }
+    }
+
+    public String findKey(int i) {
+        if (i < 0 || i > asize)
+            return null;
+        return tab[i][0];
+    }
+
+    public String findValue(int i) {
+        if (i < 0 || i > asize)
+            return null;
+        return tab[i][1];
+    }
+
+    public String findValue(String key) {
+        return findValue(key, null);
+    }
+
+    public String findValue(String k, String Default) {
+        if (k == null)
+            return Default;
+        k = k.toLowerCase(Locale.US);
+        for (int i = 0; i < asize; ++i) {
+            if (tab[i][0] == null) {
+                return Default;
+            } else if (k.equals(tab[i][0])) {
+                return tab[i][1];
+            }
+        }
+        return Default;
+    }
+
+    class ParserIterator implements Iterator<String> {
+        int index;
+        boolean returnsValue; // or key
+
+        ParserIterator (boolean returnValue) {
+            returnsValue = returnValue;
+        }
+        @Override
+        public boolean hasNext () {
+            return index<nkeys;
+        }
+        @Override
+        public String next () {
+            if (index >= nkeys)
+                throw new NoSuchElementException();
+            return tab[index++][returnsValue?1:0];
+        }
+    }
+
+    public Iterator<String> keys () {
+        return new ParserIterator (false);
+    }
+
+    public Iterator<String> values () {
+        return new ParserIterator (true);
+    }
+
+    @Override
+    public String toString () {
+        Iterator<String> k = keys();
+        StringBuilder sb = new StringBuilder();
+        sb.append("{size=").append(asize).append(" nkeys=").append(nkeys)
+                .append(' ');
+        for (int i=0; k.hasNext(); i++) {
+            String key = k.next();
+            String val = findValue (i);
+            if (val != null && "".equals (val)) {
+                val = null;
+            }
+            sb.append(" {").append(key).append(val == null ? "" : "," + val)
+                    .append('}');
+            if (k.hasNext()) {
+                sb.append (',');
+            }
+        }
+        sb.append (" }");
+        return sb.toString();
+    }
+
+    public int findInt(String k, int Default) {
+        try {
+            return Integer.parseInt(findValue(k, String.valueOf(Default)));
+        } catch (Throwable t) {
+            return Default;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Exchange.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,309 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Encapsulates one HTTP/1.1 request/responseAsync exchange.
+ */
+class Http1Exchange extends ExchangeImpl {
+
+    final HttpRequestImpl request;        // main request
+    final List<CompletableFuture<?>> operations; // used for cancel
+    final Http1Request requestAction;
+    volatile Http1Response response;
+    final HttpConnection connection;
+    final HttpClientImpl client;
+    final ExecutorWrapper executor;
+
+    @Override
+    public String toString() {
+        return request.toString();
+    }
+
+    HttpRequestImpl request() {
+        return request;
+    }
+
+    Http1Exchange(Exchange exchange, HttpConnection connection)
+        throws IOException
+    {
+        super(exchange);
+        this.request = exchange.request();
+        this.client = request.client();
+        this.executor = client.executorWrapper();
+        this.operations = Collections.synchronizedList(new LinkedList<>());
+        if (connection != null) {
+            this.connection = connection;
+        } else {
+            InetSocketAddress addr = getAddress(request);
+            this.connection = HttpConnection.getConnection(addr, request);
+        }
+        this.requestAction = new Http1Request(request, this.connection);
+    }
+
+    private static InetSocketAddress getAddress(HttpRequestImpl req) {
+        URI uri = req.uri();
+        if (uri == null) {
+            return req.authority();
+        }
+        int port = uri.getPort();
+        if (port == -1) {
+            if (uri.getScheme().equalsIgnoreCase("https")) {
+                port = 443;
+            } else {
+                port = 80;
+            }
+        }
+        String host = uri.getHost();
+        if (req.proxy() == null) {
+            return new InetSocketAddress(host, port);
+        } else {
+            return InetSocketAddress.createUnresolved(host, port);
+        }
+    }
+
+    HttpConnection connection() {
+        return connection;
+    }
+
+    @Override
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor)
+        throws IOException
+    {
+        return responseBody(processor, true);
+    }
+
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor,
+                       boolean return2Cache)
+        throws IOException
+    {
+        try {
+            T body = response.readBody(processor, return2Cache);
+            return body;
+        } catch (Throwable t) {
+            connection.close();
+            throw t;
+        }
+    }
+
+    @Override
+    <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+        CompletableFuture<T> cf = new CompletableFuture<>();
+        request.client()
+               .executorWrapper()
+               .execute(() -> {
+                            try {
+                                T body = responseBody(processor);
+                                cf.complete(body);
+                            } catch (Throwable e) {
+                                cf.completeExceptionally(e);
+                            }
+                        },
+                        () -> response.response.getAccessControlContext()); // TODO: fix
+        return cf;
+    }
+
+    @Override
+    void sendHeadersOnly() throws IOException, InterruptedException {
+        try {
+            if (!connection.connected()) {
+                connection.connect();
+            }
+            requestAction.sendHeadersOnly();
+        } catch (Throwable e) {
+            connection.close();
+            throw e;
+        }
+    }
+
+    @Override
+    void sendBody() throws IOException {
+        try {
+            requestAction.continueRequest();
+        } catch (Throwable e) {
+            connection.close();
+            throw e;
+        }
+    }
+
+    @Override
+    HttpResponseImpl getResponse() throws IOException {
+        try {
+            response = new Http1Response(connection, this);
+            response.readHeaders();
+            return response.response();
+        } catch (Throwable t) {
+            connection.close();
+            throw t;
+        }
+    }
+
+    @Override
+    void sendRequest() throws IOException, InterruptedException {
+        try {
+            if (!connection.connected()) {
+                connection.connect();
+            }
+            requestAction.sendRequest();
+        } catch (Throwable t) {
+            connection.close();
+            throw t;
+        }
+    }
+
+    private void closeConnection() {
+        connection.close();
+    }
+
+    @Override
+    CompletableFuture<Void> sendHeadersAsync() {
+        if (!connection.connected()) {
+            CompletableFuture<Void> op = connection.connectAsync()
+                    .thenCompose(this::sendHdrsAsyncImpl)
+                    .whenComplete((Void b, Throwable t) -> {
+                        if (t != null)
+                            closeConnection();
+                    });
+            operations.add(op);
+            return op;
+        } else {
+            return sendHdrsAsyncImpl(null);
+        }
+    }
+
+    private CompletableFuture<Void> sendHdrsAsyncImpl(Void v) {
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+                            try {
+                                requestAction.sendHeadersOnly();
+                                cf.complete(null);
+                            } catch (Throwable e) {
+                                cf.completeExceptionally(e);
+                                connection.close();
+                            }
+                         },
+                         () -> request.getAccessControlContext());
+        operations.add(cf);
+        return cf;
+    }
+
+    /**
+     * Cancel checks to see if request and responseAsync finished already.
+     * If not it closes the connection and completes all pending operations
+     */
+    @Override
+    synchronized void cancel() {
+        if (requestAction != null && requestAction.finished()
+                && response != null && response.finished()) {
+            return;
+        }
+        connection.close();
+        IOException e = new IOException("Request cancelled");
+        int count = 0;
+        for (CompletableFuture<?> cf : operations) {
+            cf.completeExceptionally(e);
+            count++;
+        }
+        Log.logError("Http1Exchange.cancel: count=" + count);
+    }
+
+    CompletableFuture<HttpResponseImpl> getResponseAsyncImpl(Void v) {
+        CompletableFuture<HttpResponseImpl> cf = new CompletableFuture<>();
+        try {
+            response = new Http1Response(connection, Http1Exchange.this);
+            response.readHeaders();
+            cf.complete(response.response());
+        } catch (IOException e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+
+    @Override
+    CompletableFuture<HttpResponseImpl> getResponseAsync(Void v) {
+        CompletableFuture<HttpResponseImpl> cf =
+            connection.whenReceivingResponse()
+                      .thenCompose(this::getResponseAsyncImpl);
+
+        operations.add(cf);
+        return cf;
+    }
+
+    @Override
+    CompletableFuture<Void> sendBodyAsync() {
+        final CompletableFuture<Void> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+            try {
+                requestAction.continueRequest();
+                cf.complete(null);
+            } catch (Throwable e) {
+                cf.completeExceptionally(e);
+                connection.close();
+            }
+        }, () -> request.getAccessControlContext());
+        operations.add(cf);
+        return cf;
+    }
+
+    @Override
+    CompletableFuture<Void> sendRequestAsync() {
+        CompletableFuture<Void> op;
+        if (!connection.connected()) {
+            op = connection.connectAsync()
+                .thenCompose(this::sendRequestAsyncImpl)
+                .whenComplete((Void v, Throwable t) -> {
+                    if (t != null) {
+                        closeConnection();
+                    }
+                });
+        } else {
+            op = sendRequestAsyncImpl(null);
+        }
+        operations.add(op);
+        return op;
+    }
+
+    CompletableFuture<Void> sendRequestAsyncImpl(Void v) {
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+            try {
+                requestAction.sendRequest();
+                cf.complete(null);
+            } catch (Throwable e) {
+                cf.completeExceptionally(e);
+                connection.close();
+            }
+        }, () -> request.getAccessControlContext());
+        operations.add(cf);
+        return cf;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,362 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.function.LongConsumer;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+/**
+ *  A HTTP/1.1 request.
+ *
+ * send() -> Writes the request + body to the given channel, in one blocking
+ * operation.
+ */
+class Http1Request {
+
+    final HttpRequestImpl request;
+    final HttpConnection chan;
+    // Multiple buffers are used to hold different parts of request
+    // See line 206 and below for description
+    final ByteBuffer[] buffers;
+    final HttpRequest.BodyProcessor requestProc;
+    final HttpHeadersImpl userHeaders, systemHeaders;
+    final LongConsumer flowController;
+    boolean streaming;
+    long contentLength;
+
+    Http1Request(HttpRequestImpl request, HttpConnection connection)
+        throws IOException
+    {
+        this.request = request;
+        this.chan = connection;
+        buffers = new ByteBuffer[5]; // TODO: check
+        this.requestProc = request.requestProcessor();
+        this.userHeaders = request.getUserHeaders();
+        this.systemHeaders = request.getSystemHeaders();
+        this.flowController = this::dummy;
+    }
+
+    private void logHeaders() throws IOException {
+        StringBuilder sb = new StringBuilder(256);
+        sb.append("REQUEST HEADERS:\r\n");
+        collectHeaders1(sb, request, systemHeaders);
+        collectHeaders1(sb, request, userHeaders);
+        Log.logHeaders(sb.toString());
+    }
+
+    private void dummy(long x) {
+        // not used in this class
+    }
+
+    private void collectHeaders0() throws IOException {
+        if (Log.headers()) {
+            logHeaders();
+        }
+        StringBuilder sb = new StringBuilder(256);
+        collectHeaders1(sb, request, systemHeaders);
+        collectHeaders1(sb, request, userHeaders);
+        sb.append("\r\n");
+        String headers = sb.toString();
+        buffers[1] = ByteBuffer.wrap(headers.getBytes(StandardCharsets.US_ASCII));
+    }
+
+    private void collectHeaders1(StringBuilder sb,
+                                 HttpRequestImpl request,
+                                 HttpHeadersImpl headers)
+        throws IOException
+    {
+        Map<String,List<String>> h = headers.directMap();
+        Set<Map.Entry<String,List<String>>> entries = h.entrySet();
+
+        for (Map.Entry<String,List<String>> entry : entries) {
+            String key = entry.getKey();
+            sb.append(key).append(": ");
+            List<String> values = entry.getValue();
+            int num = values.size();
+            for (String value : values) {
+                sb.append(value);
+                if (--num > 0) {
+                    sb.append(',');
+                }
+            }
+            sb.append("\r\n");
+        }
+    }
+
+    private static final int BUFSIZE = 64 * 1024; // TODO: configurable?
+
+    private String getPathAndQuery(URI uri) {
+        String path = uri.getPath();
+        String query = uri.getQuery();
+        if (path == null || path.equals("")) {
+            path = "/";
+        }
+        if (query == null) {
+            query = "";
+        }
+        if (query.equals("")) {
+            return path;
+        } else {
+            return path + "?" + query;
+        }
+    }
+
+    private String authorityString(InetSocketAddress addr) {
+        return addr.getHostString() + ":" + addr.getPort();
+    }
+
+    private String requestURI() {
+        URI uri = request.uri();
+        String method = request.method();
+
+        if ((request.proxy() == null && !method.equals("CONNECT"))
+                || request.isWebSocket()) {
+            return getPathAndQuery(uri);
+        }
+        if (request.secure()) {
+            if (request.method().equals("CONNECT")) {
+                // use authority for connect itself
+                return authorityString(request.authority());
+            } else {
+                // requests over tunnel do not require full URL
+                return getPathAndQuery(uri);
+            }
+        }
+        return uri == null? authorityString(request.authority()) : uri.toString();
+    }
+
+    void sendHeadersOnly() throws IOException {
+        collectHeaders();
+        chan.write(buffers, 0, 2);
+    }
+
+    void sendRequest() throws IOException {
+        collectHeaders();
+        if (contentLength == 0) {
+            chan.write(buffers, 0, 2);
+        } else if (contentLength > 0) {
+            writeFixedContent(true);
+        } else {
+            writeStreamedContent(true);
+        }
+        setFinished();
+    }
+
+    private boolean finished;
+
+    synchronized boolean finished() {
+        return  finished;
+    }
+
+    synchronized void setFinished() {
+        finished = true;
+    }
+
+    private void collectHeaders() throws IOException {
+        if (Log.requests() && request != null) {
+            Log.logRequest(request.toString());
+        }
+        String uriString = requestURI();
+        StringBuilder sb = new StringBuilder(64);
+        sb.append(request.method())
+          .append(' ')
+          .append(uriString)
+          .append(" HTTP/1.1\r\n");
+        String cmd = sb.toString();
+
+        buffers[0] = ByteBuffer.wrap(cmd.getBytes(StandardCharsets.US_ASCII));
+        URI uri = request.uri();
+        if (uri != null) {
+            systemHeaders.setHeader("Host", uri.getHost());
+        }
+        if (request == null) {
+            // this is not a user request. No content
+            contentLength = 0;
+        } else {
+            contentLength = requestProc.onRequestStart(request, flowController);
+        }
+
+        if (contentLength == 0) {
+            systemHeaders.setHeader("Content-Length", "0");
+            collectHeaders0();
+        } else if (contentLength > 0) {
+            /* [0] request line [1] headers [2] body  */
+            systemHeaders.setHeader("Content-Length",
+                                    Integer.toString((int) contentLength));
+            streaming = false;
+            collectHeaders0();
+            buffers[2] = chan.getBuffer();
+        } else {
+            /* Chunked:
+             *
+             * [0] request line [1] headers [2] chunk header [3] chunk data [4]
+             * final chunk header and trailing CRLF of previous chunks
+             *
+             * 2,3,4 used repeatedly */
+            streaming = true;
+            systemHeaders.setHeader("Transfer-encoding", "chunked");
+            collectHeaders0();
+            buffers[3] = chan.getBuffer();
+        }
+    }
+
+    // The following two methods used by Http1Exchange to handle expect continue
+
+    void continueRequest() throws IOException {
+        if (streaming) {
+            writeStreamedContent(false);
+        } else {
+            writeFixedContent(false);
+        }
+        setFinished();
+    }
+
+    /* Entire request is sent, or just body only  */
+    private void writeStreamedContent(boolean includeHeaders)
+        throws IOException
+    {
+        if (requestProc instanceof HttpRequest.BodyProcessor) {
+            HttpRequest.BodyProcessor pullproc = requestProc;
+            int startbuf, nbufs;
+
+            if (includeHeaders) {
+                startbuf = 0;
+                nbufs = 5;
+            } else {
+                startbuf = 2;
+                nbufs = 3;
+            }
+            try {
+                // TODO: currently each write goes out as one chunk
+                // TODO: should be collecting data and buffer it.
+
+                buffers[3].clear();
+                boolean done = pullproc.onRequestBodyChunk(buffers[3]);
+                int chunklen = buffers[3].position();
+                buffers[2] = getHeader(chunklen);
+                buffers[3].flip();
+                buffers[4] = CRLF_BUFFER();
+                chan.write(buffers, startbuf, nbufs);
+                while (!done) {
+                    buffers[3].clear();
+                    done = pullproc.onRequestBodyChunk(buffers[3]);
+                    if (done)
+                        break;
+                    buffers[3].flip();
+                    chunklen = buffers[3].remaining();
+                    buffers[2] = getHeader(chunklen);
+                    buffers[4] = CRLF_BUFFER();
+                    chan.write(buffers, 2, 3);
+                }
+                buffers[3] = EMPTY_CHUNK_HEADER();
+                buffers[4] = CRLF_BUFFER();
+                chan.write(buffers, 3, 2);
+            } catch (IOException e) {
+                requestProc.onRequestError(e);
+                throw e;
+            }
+        }
+    }
+    /* Entire request is sent, or just body only */
+    private void writeFixedContent(boolean includeHeaders)
+        throws IOException
+    {
+        try {
+            int startbuf, nbufs;
+
+            if (contentLength == 0) {
+                return;
+            }
+            if (includeHeaders) {
+                startbuf = 0;
+                nbufs = 3;
+            } else {
+                startbuf = 2;
+                nbufs = 1;
+                buffers[0].clear().flip();
+                buffers[1].clear().flip();
+            }
+            buffers[2] = chan.getBuffer();
+            if (requestProc instanceof HttpRequest.BodyProcessor) {
+                HttpRequest.BodyProcessor pullproc = requestProc;
+
+                boolean done = pullproc.onRequestBodyChunk(buffers[2]);
+                buffers[2].flip();
+                long headersLength = buffers[0].remaining() + buffers[1].remaining();
+                long contentWritten = buffers[2].remaining();
+                chan.checkWrite(headersLength + contentWritten,
+                                buffers,
+                                startbuf,
+                                nbufs);
+                while (!done) {
+                    buffers[2].clear();
+                    done = pullproc.onRequestBodyChunk(buffers[2]);
+                    buffers[2].flip();
+                    long len = buffers[2].remaining();
+                    if (contentWritten + len > contentLength) {
+                        break;
+                    }
+                    chan.checkWrite(len, buffers[2]);
+                    contentWritten += len;
+                }
+                if (contentWritten != contentLength) {
+                    throw new IOException("wrong content length");
+                }
+            }
+        } catch (IOException e) {
+            requestProc.onRequestError(e);
+            throw e;
+        }
+    }
+
+    private static final byte[] CRLF = {'\r', '\n'};
+    private static final byte[] EMPTY_CHUNK_BYTES = {'0', '\r', '\n'};
+
+    private ByteBuffer CRLF_BUFFER() {
+        return ByteBuffer.wrap(CRLF);
+    }
+
+    private ByteBuffer EMPTY_CHUNK_HEADER() {
+        return ByteBuffer.wrap(EMPTY_CHUNK_BYTES);
+    }
+
+    /* Returns a header for a particular chunk size */
+    private static ByteBuffer getHeader(int size){
+        String hexStr =  Integer.toHexString(size);
+        byte[] hexBytes = hexStr.getBytes(US_ASCII);
+        byte[] header = new byte[hexStr.length()+2];
+        System.arraycopy(hexBytes, 0, header, 0, hexBytes.length);
+        header[hexBytes.length] = CRLF[0];
+        header[hexBytes.length+1] = CRLF[1];
+        return ByteBuffer.wrap(header);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,290 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.LongConsumer;
+import static java.net.http.HttpClient.Version.HTTP_1_1;
+
+/**
+ * Handles a HTTP/1.1 response in two blocking calls. readHeaders() and
+ * readBody(). There can be more than one of these per Http exchange.
+ */
+class Http1Response {
+
+    private ResponseContent content;
+    private final HttpRequestImpl request;
+    HttpResponseImpl response;
+    private final HttpConnection connection;
+    private ResponseHeaders headers;
+    private int responseCode;
+    private ByteBuffer buffer; // same buffer used for reading status line and headers
+    private final Http1Exchange exchange;
+    private final boolean redirecting; // redirecting
+    private boolean return2Cache; // return connection to cache when finished
+
+    Http1Response(HttpConnection conn, Http1Exchange exchange) {
+        this.request = exchange.request();
+        this.exchange = exchange;
+        this.connection = conn;
+        this.redirecting = false;
+        buffer = connection.getRemaining();
+    }
+
+    // called when the initial read should come from a buffer left
+    // over from a previous response.
+    void setBuffer(ByteBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void readHeaders() throws IOException {
+        String statusline = readStatusLine();
+        if (statusline == null) {
+            if (Log.errors()) {
+                Log.logError("Connection closed. Retry");
+            }
+            connection.close();
+            // connection was closed
+            throw new IOException("Connection closed");
+        }
+        if (!statusline.startsWith("HTTP/1.")) {
+            throw new IOException("Invalid status line: " + statusline);
+        }
+        char c = statusline.charAt(7);
+        responseCode = Integer.parseInt(statusline.substring(9, 12));
+
+        headers = new ResponseHeaders(connection, buffer);
+        headers.initHeaders();
+        if (Log.headers()) {
+            logHeaders(headers);
+        }
+        response = new HttpResponseImpl(responseCode,
+                                        exchange.exchange,
+                                        headers,
+                                        null,
+                                        connection.sslParameters(),
+                                        HTTP_1_1,
+                                        connection);
+    }
+
+    private boolean finished;
+
+    synchronized void completed() {
+        finished = true;
+    }
+
+    synchronized boolean finished() {
+        return finished;
+    }
+
+    // Blocking flow controller implementation. Only works when a
+    // thread is dedicated to reading response body
+
+    static class FlowController implements LongConsumer {
+        long window ;
+
+        @Override
+        public synchronized void accept(long value) {
+            window += value;
+            notifyAll();
+        }
+
+        public synchronized void request(long value) throws InterruptedException {
+            while (window < value) {
+                wait();
+            }
+            window -= value;
+        }
+    }
+
+    FlowController flowController;
+
+    int fixupContentLen(int clen) {
+        if (request.method().equalsIgnoreCase("HEAD")) {
+            return 0;
+        }
+        if (clen == -1) {
+            if (headers.firstValue("Transfer-encoding").orElse("")
+                       .equalsIgnoreCase("chunked")) {
+                return -1;
+            }
+            return 0;
+        }
+        return clen;
+    }
+
+    private void returnBuffer(ByteBuffer buf) {
+        // not currently used, but will be when we change SSL to use fixed
+        // sized buffers and a single buffer pool for HttpClientImpl
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T readBody(java.net.http.HttpResponse.BodyProcessor<T> p,
+                          boolean return2Cache)
+        throws IOException
+    {
+        T body = null; // TODO: check null case below
+        this.return2Cache = return2Cache;
+        final java.net.http.HttpResponse.BodyProcessor<T> pusher = p;
+
+        int clen0 = headers.getContentLength();
+        final int clen = fixupContentLen(clen0);
+
+        flowController = new FlowController();
+
+        body = pusher.onResponseBodyStart(clen, headers, flowController);
+
+        ExecutorWrapper executor;
+        if (body == null) {
+            executor = ExecutorWrapper.callingThread();
+        } else {
+            executor = request.client().executorWrapper();
+        }
+
+        final ResponseHeaders h = headers;
+        if (body == null) {
+            content = new ResponseContent(connection,
+                                          clen,
+                                          h,
+                                          pusher,
+                                          flowController);
+            content.pushBody(headers.getResidue());
+            body = pusher.onResponseComplete();
+            completed();
+            onFinished();
+            return body;
+        } else {
+            executor.execute(() -> {
+                    try {
+                        content = new ResponseContent(connection,
+                                                      clen,
+                                                      h,
+                                                      pusher,
+                                                      flowController);
+                        content.pushBody(headers.getResidue());
+                        pusher.onResponseComplete();
+                        completed();
+                        onFinished();
+                    } catch (Throwable e) {
+                        pusher.onResponseError(e);
+                    }
+                },
+                () -> response.getAccessControlContext());
+        }
+        return body;
+    }
+
+    private void onFinished() {
+        connection.buffer = content.getResidue();
+        if (return2Cache) {
+            connection.returnToCache(headers);
+        }
+    }
+
+    private void logHeaders(ResponseHeaders headers) {
+        Map<String, List<String>> h = headers.mapInternal();
+        Set<String> keys = h.keySet();
+        Set<Map.Entry<String, List<String>>> entries = h.entrySet();
+        for (Map.Entry<String, List<String>> entry : entries) {
+            String key = entry.getKey();
+            StringBuilder sb = new StringBuilder();
+            sb.append(key).append(": ");
+            List<String> values = entry.getValue();
+            if (values != null) {
+                for (String value : values) {
+                    sb.append(value).append(' ');
+                }
+            }
+            Log.logHeaders(sb.toString());
+        }
+    }
+
+    HttpResponseImpl response() {
+        return response;
+    }
+
+    boolean redirecting() {
+        return redirecting;
+    }
+
+    HttpHeaders responseHeaders() {
+        return headers;
+    }
+
+    int responseCode() {
+        return responseCode;
+    }
+
+    static final char CR = '\r';
+    static final char LF = '\n';
+
+    private ByteBuffer getBuffer() throws IOException {
+        if (buffer == null || !buffer.hasRemaining()) {
+            buffer = connection.read();
+        }
+        return buffer;
+    }
+
+    ByteBuffer buffer() {
+        return buffer;
+    }
+
+    String readStatusLine() throws IOException {
+        boolean cr = false;
+        StringBuilder statusLine = new StringBuilder(128);
+        ByteBuffer b;
+        while ((b = getBuffer()) != null) {
+            byte[] buf = b.array();
+            int offset = b.position();
+            int len = b.limit() - offset;
+
+            for (int i = 0; i < len; i++) {
+                char c = (char) buf[i+offset];
+
+                if (cr) {
+                    if (c == LF) {
+                        b.position(i + 1 + offset);
+                        return statusLine.toString();
+                    } else {
+                        throw new IOException("invalid status line");
+                    }
+                }
+                if (c == CR) {
+                    cr = true;
+                } else {
+                    statusLine.append(c);
+                }
+            }
+            // unlikely, but possible, that multiple reads required
+            b.position(b.limit());
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+class Http2ClientImpl {
+    Http2ClientImpl(HttpClientImpl t) {}
+    String getSettingsString() {return "";}
+    void debugPrint() {}
+    Http2Connection getConnectionFor(HttpRequestImpl r) {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.Authenticator;
+import java.net.CookieManager;
+import java.net.ProxySelector;
+import java.net.URI;
+import static java.net.http.Utils.BUFSIZE;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import static java.nio.channels.SelectionKey.OP_CONNECT;
+import static java.nio.channels.SelectionKey.OP_READ;
+import static java.nio.channels.SelectionKey.OP_WRITE;
+import java.nio.channels.Selector;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.*;
+import java.security.NoSuchAlgorithmException;
+import java.util.ListIterator;
+import java.util.Optional;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+class Http2Connection {
+    static CompletableFuture<Http2Connection> createAsync(
+        HttpConnection connection, Http2ClientImpl client2, Exchange exchange) {
+            return null;
+        }
+
+    Http2Connection(HttpConnection connection, Http2ClientImpl client2,
+            Exchange exchange) throws IOException, InterruptedException {
+    }
+
+    Stream getStream(int i) {return null;}
+    Stream createStream(Exchange ex) {return null;}
+    void putConnection() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClient.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,415 @@
+/*
+ * 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.Authenticator;
+import java.net.CookieManager;
+import java.net.InetSocketAddress;
+import java.net.NetPermission;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * A container for configuration information common to multiple {@link
+ * HttpRequest}s. All requests are associated with, and created from a {@code
+ * HttpClient}.
+ *
+ * <p> {@code HttpClient}s are immutable and created from a builder returned
+ * from {@link HttpClient#create()}. Request builders that are associated with
+ * an application created client, are created by calling {@link #request(URI) }.
+ * It is also possible to create a request builder directly which is associated
+ * with the <i>default</i> {@code HttpClient} by calling {@link
+ * HttpRequest#create(URI)}.
+ *
+ * <p> The HTTP API functions asynchronously (using {@link
+ * java.util.concurrent.CompletableFuture}) and also in a simple synchronous
+ * mode, where all work may be done on the calling thread. In asynchronous mode,
+ * work is done on the threads supplied by the client's {@link
+ * java.util.concurrent.ExecutorService}.
+ *
+ * <p> <a name="defaultclient"></a> The <i>default</i> {@code HttpClient} is
+ * used whenever a request is created without specifying a client explicitly
+ * (by calling {@link HttpRequest#create(java.net.URI) HttpRequest.create}).
+ * There is only one static instance of this {@code HttpClient}. A reference to
+ * the default client can be obtained by calling {@link #getDefault() }. If a
+ * security manager is set, then a permission is required for this.
+ *
+ * <p> See {@link HttpRequest} for examples of usage of this API.
+ *
+ * @since 9
+ */
+public abstract class HttpClient {
+
+    HttpClient() {}
+
+    private static HttpClient defaultClient;
+
+    /**
+     * Creates a new {@code HttpClient} builder.
+     *
+     * @return a {@code HttpClient.Builder}
+     */
+    public static Builder  create() {
+        return new HttpClientBuilderImpl();
+    }
+
+    //public abstract void debugPrint();
+
+    /**
+     * Returns the default {@code HttpClient} that is used when a {@link
+     * HttpRequest} is created without specifying a client. If a security
+     * manager is set, then its {@code checkPermission} method is called with a
+     * {@link java.net.NetPermission} specifying the name "getDefaultHttpClient".
+     * If the caller does not possess this permission a {@code SecurityException}
+     * is thrown.
+     *
+     * @implNote Code running under a security manager can avoid the security
+     * manager check by creating a {@code HttpClient} explicitly.
+     *
+     * @return the default {@code HttpClient}
+     * @throws SecurityException if the caller does not have the required
+     *                           permission
+     */
+    public synchronized static HttpClient getDefault() {
+        Utils.checkNetPermission("getDefaultHttpClient");
+        if (defaultClient == null) {
+            Builder b = create();
+            defaultClient = b.executorService(Executors.newCachedThreadPool())
+                             .build();
+        }
+        return defaultClient;
+    }
+
+    /**
+     * Creates a {@code HttpRequest} builder associated with this client.
+     *
+     * @return a new builder
+     */
+    public abstract HttpRequest.Builder request();
+
+    /**
+     * Creates a {@code HttpRequest} builder associated with this client and
+     * using the given request URI.
+     *
+     * @param uri the request URI
+     * @return a new builder
+     */
+    public abstract HttpRequest.Builder request(URI uri);
+
+    /**
+     * A builder of immutable {@link HttpClient}s. {@code HttpClient.Builder}s
+     * are created by calling {@link HttpClient#create()}.
+     *
+     * <p> Each of the setter methods in this class modifies the state of the
+     * builder and returns <i>this</i> (ie. the same instance). The methods are
+     * not synchronized and should not be called from multiple threads without
+     * external synchronization.
+     *
+     * <p> {@link #build() } returns a new {@code HttpClient} each time it is
+     * called.
+     *
+     * @since 9
+     */
+    public abstract static class Builder {
+
+        Builder() {}
+
+        /**
+         * Sets a cookie manager.
+         *
+         * @param manager the CookieManager
+         * @return this builder
+         * @throws NullPointerException if {@code manager} is null
+         */
+        public abstract Builder cookieManager(CookieManager manager);
+
+        /**
+         * Sets an SSLContext. If a security manager is set, then the caller
+         * must have the {@link java.net.NetPermission NetPermission}
+         * ("setSSLContext")
+         *
+         * <p> The effect of not calling this method, is that a default {@link
+         * javax.net.ssl.SSLContext} is used, which is normally adequate for
+         * client applications that do not need to specify protocols, or require
+         * client authentication.
+         *
+         * @param sslContext the SSLContext
+         * @return this builder
+         * @throws NullPointerException if {@code sslContext} is null
+         * @throws SecurityException if a security manager is set and the
+         *                           caller does not have any required permission
+         */
+        public abstract Builder sslContext(SSLContext sslContext);
+
+        /**
+         * Sets an SSLParameters. If this method is not called, then a default
+         * set of parameters are used. The contents of the given object are
+         * copied. Some parameters which are used internally by the HTTP protocol
+         * implementation (such as application protocol list) should not be set
+         * by callers, as they are ignored.
+         *
+         * @param sslParameters the SSLParameters
+         * @return this builder
+         * @throws NullPointerException if {@code sslParameters} is null
+         */
+        public abstract Builder sslParameters(SSLParameters sslParameters);
+
+        /**
+         * Sets the ExecutorService to be used for sending and receiving
+         * asynchronous requests. If this method is not called, a default
+         * executor service is set, which is the one returned from {@link
+         * java.util.concurrent.Executors#newCachedThreadPool()
+         * Executors.newCachedThreadPool}.
+         *
+         * @param s the ExecutorService
+         * @return this builder
+         * @throws NullPointerException if {@code s} is null
+         */
+        public abstract Builder executorService(ExecutorService s);
+
+        /**
+         * Specifies whether requests will automatically follow redirects issued
+         * by the server. This setting can be overridden on each request. The
+         * default value for this setting is {@link Redirect#NEVER NEVER}
+         *
+         * @param policy the redirection policy
+         * @return this builder
+         * @throws NullPointerException if {@code policy} is null
+         */
+        public abstract Builder followRedirects(Redirect policy);
+
+        /**
+         * Requests a specific HTTP protocol version where possible. If not set,
+         * the version defaults to {@link HttpClient.Version#HTTP_1_1}. If
+         * {@link HttpClient.Version#HTTP_2} is set, then each request will
+         * attempt to upgrade to HTTP/2.  If the upgrade succeeds, then the
+         * response to this request will use HTTP/2 and all subsequent requests
+         * and responses to the same
+         * <a href="https://tools.ietf.org/html/rfc6454#section-4">origin server</a>
+         * will use HTTP/2. If the upgrade fails, then the response will be
+         * handled using HTTP/1.1
+         *
+         * <p>This setting can be over-ridden per request.
+         *
+         * @param version the requested HTTP protocol version
+         * @return this builder
+         * @throws NullPointerException if {@code version} is null
+         */
+        public abstract Builder version(HttpClient.Version version);
+
+        /**
+         * Sets the default priority for any HTTP/2 requests sent from this
+         * client. The value provided must be between {@code 1} and {@code 255}.
+         *
+         * @param priority the priority weighting
+         * @return this builder
+         * @throws IllegalArgumentException if the given priority is out of range
+         */
+        public abstract Builder priority(int priority);
+
+        /**
+         * Enables pipelining mode for HTTP/1.1 requests sent through this
+         * client. When pipelining is enabled requests to the same destination
+         * are sent over existing TCP connections that may already have requests
+         * outstanding. This reduces the number of connections, but may have
+         * a performance impact since responses must be delivered in the same
+         * order that they were sent. By default, pipelining is disabled.
+         *
+         * @param enable {@code true} enables pipelining
+         * @return this builder
+         * @throws UnsupportedOperationException if pipelining mode is not
+         *                                       supported by this implementation
+         */
+        public abstract Builder pipelining(boolean enable);
+
+        /**
+         * Sets a {@link java.net.ProxySelector} for this client. If no selector
+         * is set, then no proxies are used. If a {@code null} parameter is
+         * given then the system wide default proxy selector is used.
+         *
+         * @implNote {@link java.net.ProxySelector#of(InetSocketAddress)}
+         * provides a ProxySelector which uses one proxy for all requests.
+         *
+         * @param selector the ProxySelector
+         * @return this builder
+         */
+        public abstract Builder proxy(ProxySelector selector);
+
+        /**
+         * Sets an authenticator to use for HTTP authentication.
+         *
+         * @param a the Authenticator
+         * @return this builder
+         */
+        public abstract Builder authenticator(Authenticator a);
+
+        /**
+         * Returns a {@link HttpClient} built from the current state of this
+         * builder.
+         *
+         * @return this builder
+         */
+        public abstract HttpClient build();
+    }
+
+
+    /**
+     * Returns an {@code Optional} which contains this client's {@link
+     * CookieManager}. If no CookieManager was set in this client's builder,
+     * then the {@code Optional} is empty.
+     *
+     * @return an {@code Optional} containing this client's CookieManager
+     */
+    public abstract Optional<CookieManager> cookieManager();
+
+    /**
+     * Returns the follow-redirects setting for this client. The default value
+     * for this setting is {@link HttpClient.Redirect#NEVER}
+     *
+     * @return this client's follow redirects setting
+     */
+    public abstract Redirect followRedirects();
+
+    /**
+     * Returns an {@code Optional} containing the ProxySelector for this client.
+     * If no proxy is set then the {@code Optional} is empty.
+     *
+     * @return an {@code Optional} containing this client's proxy selector
+     */
+    public abstract Optional<ProxySelector> proxy();
+
+    /**
+     * Returns the SSLContext, if one was set on this client. If a security
+     * manager is set then then caller must then the caller must have the
+     * {@link java.net.NetPermission NetPermission}("getSSLContext") permission.
+     * If no SSLContext was set, then the default context is returned.
+     *
+     * @return this client's SSLContext
+     */
+    public abstract SSLContext sslContext();
+
+    /**
+     * Returns an {@code Optional} containing the {@link SSLParameters} set on
+     * this client. If no {@code SSLParameters} were set in the client's builder,
+     * then the {@code Optional} is empty.
+     *
+     * @return an {@code Optional} containing this client's SSLParameters
+     */
+    public abstract Optional<SSLParameters> sslParameters();
+
+    /**
+     * Returns an {@code Optional} containing the {@link Authenticator} set on
+     * this client. If no {@code Authenticator} was set in the client's builder,
+     * then the {@code Optional} is empty.
+     *
+     * @return an {@code Optional} containing this client's Authenticator
+     */
+    public abstract Optional<Authenticator> authenticator();
+
+    /**
+     * Returns the HTTP protocol version requested for this client. The default
+     * value is {@link HttpClient.Version#HTTP_1_1}
+     *
+     * @return the HTTP protocol version requested
+     */
+    public abstract HttpClient.Version version();
+
+    /**
+     * Returns whether this client supports HTTP/1.1 pipelining.
+     *
+     * @return whether pipelining allowed
+     */
+    public abstract boolean pipelining();
+
+    /**
+     * Returns the {@code ExecutorService} set on this client. If an {@code
+     * ExecutorService} was not set on the client's builder, then a default
+     * object is returned. The default ExecutorService is created independently
+     * for each client.
+     *
+     * @return this client's ExecutorService
+     */
+    public abstract ExecutorService executorService();
+
+    /**
+     * The HTTP protocol version.
+     *
+     * @since 9
+     */
+    public static enum Version {
+
+        /**
+         * HTTP version 1.1
+         */
+        HTTP_1_1,
+
+        /**
+         * HTTP version 2
+         */
+        HTTP_2
+    }
+
+    /**
+     * Defines automatic redirection policy. This is checked whenever a 3XX
+     * response code is received. If redirection does not happen automatically
+     * then the response is returned to the user, where it can be handled
+     * manually.
+     *
+     * <p> {@code Redirect} policy is set via the {@link
+     * HttpClient.Builder#followRedirects(HttpClient.Redirect)} method.
+     *
+     * @since 9
+     */
+    public static enum Redirect {
+
+        /**
+         * Never redirect.
+         */
+        NEVER,
+
+        /**
+         * Always redirect.
+         */
+        ALWAYS,
+
+        /**
+         * Redirect to same protocol only. Redirection may occur from HTTP URLs
+         * to other HTTP URLs, and from HTTPS URLs to other HTTPS URLs.
+         */
+        SAME_PROTOCOL,
+
+        /**
+         * Redirect always except from HTTPS URLs to HTTP URLs.
+         */
+        SECURE
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientBuilderImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,133 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.net.Authenticator;
+import java.net.CookieManager;
+import java.net.ProxySelector;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+class HttpClientBuilderImpl extends HttpClient.Builder {
+
+    CookieManager cookieManager;
+    HttpClient.Redirect followRedirects;
+    ProxySelector proxy;
+    Authenticator authenticator;
+    HttpClient.Version version = HttpClient.Version.HTTP_1_1;
+    ExecutorService executor;
+    // Security parameters
+    SSLContext sslContext;
+    SSLParameters sslParams;
+    int priority = -1;
+
+    @Override
+    public HttpClientBuilderImpl cookieManager(CookieManager manager) {
+        Objects.requireNonNull(manager);
+        this.cookieManager = manager;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl sslContext(SSLContext sslContext) {
+        Objects.requireNonNull(sslContext);
+        Utils.checkNetPermission("setSSLContext");
+        this.sslContext = sslContext;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl sslParameters(SSLParameters sslParameters) {
+        Objects.requireNonNull(sslParameters);
+        this.sslParams = sslParameters;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl executorService(ExecutorService s) {
+        Objects.requireNonNull(s);
+        this.executor = s;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl followRedirects(HttpClient.Redirect policy) {
+        Objects.requireNonNull(policy);
+        this.followRedirects = policy;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl version(HttpClient.Version version) {
+        Objects.requireNonNull(version);
+        this.version = version;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl priority(int priority) {
+        if (priority < 1 || priority > 255) {
+            throw new IllegalArgumentException("priority must be between 1 and 255");
+        }
+        this.priority = priority;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl pipelining(boolean enable) {
+        //To change body of generated methods, choose Tools | Templates.
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl proxy(ProxySelector proxy) {
+        Objects.requireNonNull(proxy);
+        this.proxy = proxy;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl authenticator(Authenticator a) {
+        Objects.requireNonNull(a);
+        this.authenticator = a;
+        return this;
+    }
+
+    @Override
+    public HttpClient build() {
+        return HttpClientImpl.create(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,499 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.Authenticator;
+import java.net.CookieManager;
+import java.net.ProxySelector;
+import java.net.URI;
+import static java.net.http.Utils.BUFSIZE;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import static java.nio.channels.SelectionKey.OP_CONNECT;
+import static java.nio.channels.SelectionKey.OP_READ;
+import static java.nio.channels.SelectionKey.OP_WRITE;
+import java.nio.channels.Selector;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.security.NoSuchAlgorithmException;
+import java.util.ListIterator;
+import java.util.Optional;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * Client implementation. Contains all configuration information and also
+ * the selector manager thread which allows async events to be registered
+ * and delivered when they occur. See AsyncEvent.
+ */
+class HttpClientImpl extends HttpClient implements BufferHandler {
+
+    private final CookieManager cookieManager;
+    private final Redirect followRedirects;
+    private final ProxySelector proxySelector;
+    private final Authenticator authenticator;
+    private final Version version;
+    private boolean pipelining = false;
+    private final ConnectionPool connections;
+    private final ExecutorWrapper executor;
+    // Security parameters
+    private final SSLContext sslContext;
+    private final SSLParameters sslParams;
+    private final SelectorManager selmgr;
+    private final FilterFactory filters;
+    private final Http2ClientImpl client2;
+    private static final ThreadFactory defaultFactory = Executors.defaultThreadFactory();
+    private final LinkedList<TimeoutEvent> timeouts;
+
+    //@Override
+    void debugPrint() {
+        selmgr.debugPrint();
+        client2.debugPrint();
+    }
+
+    public static HttpClientImpl create(HttpClientBuilderImpl builder) {
+        HttpClientImpl impl = new HttpClientImpl(builder);
+        impl.start();
+        return impl;
+    }
+
+    private HttpClientImpl(HttpClientBuilderImpl builder) {
+        if (builder.sslContext == null) {
+            try {
+                sslContext = SSLContext.getDefault();
+            } catch (NoSuchAlgorithmException ex) {
+                throw new InternalError(ex);
+            }
+        } else {
+            sslContext = builder.sslContext;
+        }
+        ExecutorService ex = builder.executor;
+        if (ex == null) {
+            ex = Executors.newCachedThreadPool((r) -> {
+                Thread t = defaultFactory.newThread(r);
+                t.setDaemon(true);
+                return t;
+            });
+        } else {
+            ex = builder.executor;
+        }
+        client2 = new Http2ClientImpl(this);
+        executor = ExecutorWrapper.wrap(ex);
+        cookieManager = builder.cookieManager;
+        followRedirects = builder.followRedirects == null ?
+                Redirect.NEVER : builder.followRedirects;
+        this.proxySelector = builder.proxy;
+        authenticator = builder.authenticator;
+        version = builder.version;
+        sslParams = builder.sslParams;
+        connections = new ConnectionPool();
+        connections.start();
+        timeouts = new LinkedList<>();
+        try {
+            selmgr = new SelectorManager();
+        } catch (IOException e) {
+            // unlikely
+            throw new InternalError(e);
+        }
+        selmgr.setDaemon(true);
+        selmgr.setName("HttpSelector");
+        filters = new FilterFactory();
+        initFilters();
+    }
+
+    private void start() {
+        selmgr.start();
+    }
+
+    /**
+     * Wait for activity on given exchange (assuming blocking = false).
+     * It's a no-op if blocking = true. In particular, the following occurs
+     * in the SelectorManager thread.
+     *
+     *  1) mark the connection non-blocking
+     *  2) add to selector
+     *  3) If selector fires for this exchange then
+     *  4)   - mark connection as blocking
+     *  5)   - call AsyncEvent.handle()
+     *
+     *  If exchange needs to block again, then call registerEvent() again
+     */
+    void registerEvent(AsyncEvent exchange) throws IOException {
+        selmgr.register(exchange);
+    }
+
+    Http2ClientImpl client2() {
+        return client2;
+    }
+
+    LinkedList<ByteBuffer> freelist = new LinkedList<>();
+
+    @Override
+    public synchronized ByteBuffer getBuffer() {
+        if (freelist.isEmpty()) {
+            return ByteBuffer.allocate(BUFSIZE);
+        }
+        return freelist.removeFirst();
+    }
+
+    @Override
+    public synchronized void returnBuffer(ByteBuffer buffer) {
+        buffer.clear();
+        freelist.add(buffer);
+    }
+
+
+    // Main loop for this client's selector
+
+    class SelectorManager extends Thread {
+
+        final Selector selector;
+        boolean closed;
+
+        final List<AsyncEvent> readyList;
+        final List<AsyncEvent> registrations;
+
+        List<AsyncEvent> debugList;
+
+        SelectorManager() throws IOException {
+            readyList = new LinkedList<>();
+            registrations = new LinkedList<>();
+            debugList = new LinkedList<>();
+            selector = Selector.open();
+        }
+
+        // This returns immediately. So caller not allowed to send/receive
+        // on connection.
+
+        synchronized void register(AsyncEvent e) throws IOException {
+            registrations.add(e);
+            selector.wakeup();
+        }
+
+        void wakeupSelector() {
+            selector.wakeup();
+        }
+
+        synchronized void shutdown() {
+            closed = true;
+            try {
+                selector.close();
+            } catch (IOException e) {}
+        }
+
+        private List<AsyncEvent> copy(List<AsyncEvent> list) {
+            LinkedList<AsyncEvent> c = new LinkedList<>();
+            for (AsyncEvent e : list) {
+                c.add(e);
+            }
+            return c;
+        }
+
+        synchronized void debugPrint() {
+            System.err.println("Selecting on:");
+            for (AsyncEvent e : debugList) {
+                System.err.println(opvals(e.interestOps()));
+            }
+        }
+
+        String opvals(int i) {
+            StringBuilder sb = new StringBuilder();
+            if ((i & OP_READ) != 0)
+                sb.append("OP_READ ");
+            if ((i & OP_CONNECT) != 0)
+                sb.append("OP_CONNECT ");
+            if ((i & OP_WRITE) != 0)
+                sb.append("OP_WRITE ");
+            return sb.toString();
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (true) {
+                    synchronized (this) {
+                        debugList = copy(registrations);
+                        for (AsyncEvent exchange : registrations) {
+                            SelectableChannel c = exchange.channel();
+                            try {
+                                c.configureBlocking(false);
+                                c.register(selector,
+                                           exchange.interestOps(),
+                                           exchange);
+                            } catch (IOException e) {
+                                Log.logError("HttpClientImpl: " + e);
+                                c.close();
+                                // let the exchange deal with it
+                                handleEvent(exchange);
+                            }
+                        }
+                        registrations.clear();
+                    }
+                    long timeval = getTimeoutValue();
+                    long now = System.currentTimeMillis();
+                    int n = selector.select(timeval);
+                    if (n == 0) {
+                        signalTimeouts(now);
+                        continue;
+                    }
+                    Set<SelectionKey> keys = selector.selectedKeys();
+
+                    for (SelectionKey key : keys) {
+                        if (key.isReadable() || key.isConnectable() || key.isWritable()) {
+                            key.cancel();
+                            AsyncEvent exchange = (AsyncEvent) key.attachment();
+                            readyList.add(exchange);
+                        }
+                    }
+                    selector.selectNow(); // complete cancellation
+                    selector.selectedKeys().clear();
+
+                    for (AsyncEvent exchange : readyList) {
+                        if (exchange instanceof AsyncEvent.Blocking) {
+                            exchange.channel().configureBlocking(true);
+                        } else {
+                            assert exchange instanceof AsyncEvent.NonBlocking;
+                        }
+                        executor.synchronize();
+                        handleEvent(exchange); // will be delegated to executor
+                    }
+                    readyList.clear();
+                }
+            } catch (Throwable e) {
+                if (!closed) {
+                    System.err.println("HttpClientImpl terminating on error");
+                    // This terminates thread. So, better just print stack trace
+                    String err = Utils.stackTrace(e);
+                    Log.logError("HttpClientImpl: fatal error: " + err);
+                }
+            }
+        }
+
+        void handleEvent(AsyncEvent e) {
+            if (closed) {
+                e.abort();
+            } else {
+                e.handle();
+            }
+        }
+    }
+
+    /**
+     * Creates a HttpRequest associated with this group.
+     *
+     * @throws IllegalStateException if the group has been stopped
+     */
+    @Override
+    public HttpRequestBuilderImpl request() {
+        return new HttpRequestBuilderImpl(this, null);
+    }
+
+    /**
+     * Creates a HttpRequest associated with this group.
+     *
+     * @throws IllegalStateException if the group has been stopped
+     */
+    @Override
+    public HttpRequestBuilderImpl request(URI uri) {
+        return new HttpRequestBuilderImpl(this, uri);
+    }
+
+    @Override
+    public SSLContext sslContext() {
+        Utils.checkNetPermission("getSSLContext");
+        return sslContext;
+    }
+
+    @Override
+    public Optional<SSLParameters> sslParameters() {
+        return Optional.ofNullable(sslParams);
+    }
+
+    @Override
+    public Optional<Authenticator> authenticator() {
+        return Optional.ofNullable(authenticator);
+    }
+
+    @Override
+    public ExecutorService executorService() {
+        return executor.userExecutor();
+    }
+
+    ExecutorWrapper executorWrapper() {
+        return executor;
+    }
+
+    @Override
+    public boolean pipelining() {
+        return this.pipelining;
+    }
+
+    ConnectionPool connectionPool() {
+        return connections;
+    }
+
+    @Override
+    public Redirect followRedirects() {
+        return followRedirects;
+    }
+
+
+    @Override
+    public Optional<CookieManager> cookieManager() {
+        return Optional.ofNullable(cookieManager);
+    }
+
+    @Override
+    public Optional<ProxySelector> proxy() {
+        return Optional.ofNullable(this.proxySelector);
+    }
+
+    @Override
+    public Version version() {
+        return version;
+    }
+
+    //private final HashMap<String, Boolean> http2NotSupported = new HashMap<>();
+
+    boolean getHttp2Allowed() {
+        return version.equals(Version.HTTP_2);
+    }
+
+    //void setHttp2NotSupported(String host) {
+        //http2NotSupported.put(host, false);
+    //}
+
+    final void initFilters() {
+        addFilter(AuthenticationFilter.class);
+        addFilter(RedirectFilter.class);
+    }
+
+    final void addFilter(Class<? extends HeaderFilter> f) {
+        filters.addFilter(f);
+    }
+
+    final List<HeaderFilter> filterChain() {
+        return filters.getFilterChain();
+    }
+
+    // Timer controls. Timers are implemented through timed Selector.select()
+    // calls.
+    synchronized void registerTimer(TimeoutEvent event) {
+        long elapse = event.timevalMillis();
+        ListIterator<TimeoutEvent> iter = timeouts.listIterator();
+        long listval = 0;
+        event.delta = event.timeval; // in case list empty
+        TimeoutEvent next;
+        while (iter.hasNext()) {
+            next = iter.next();
+            listval += next.delta;
+            if (elapse < listval) {
+                listval -= next.delta;
+                event.delta = elapse - listval;
+                next.delta -= event.delta;
+                iter.previous();
+                break;
+            } else if (!iter.hasNext()) {
+                event.delta = event.timeval - listval ;
+            }
+        }
+        iter.add(event);
+        //debugPrintList("register");
+        selmgr.wakeupSelector();
+    }
+
+    void debugPrintList(String s) {
+        System.err.printf("%s: {", s);
+        for (TimeoutEvent e : timeouts) {
+            System.err.printf("(%d,%d) ", e.delta, e.timeval);
+        }
+        System.err.println("}");
+    }
+
+    synchronized void signalTimeouts(long then) {
+        if (timeouts.isEmpty()) {
+            return;
+        }
+        long now = System.currentTimeMillis();
+        long duration = now - then;
+        ListIterator<TimeoutEvent> iter = timeouts.listIterator();
+        TimeoutEvent event = iter.next();
+        long delta = event.delta;
+        if (duration < delta) {
+            event.delta -= duration;
+            return;
+        }
+        event.handle();
+        iter.remove();
+        while (iter.hasNext()) {
+            event = iter.next();
+            if (event.delta == 0) {
+                event.handle();
+                iter.remove();
+            } else {
+                event.delta += delta;
+                break;
+            }
+        }
+        //debugPrintList("signalTimeouts");
+    }
+
+    synchronized void cancelTimer(TimeoutEvent event) {
+        ListIterator<TimeoutEvent> iter = timeouts.listIterator();
+        while (iter.hasNext()) {
+            TimeoutEvent ev = iter.next();
+            if (event == ev) {
+                if (iter.hasNext()) {
+                    // adjust
+                    TimeoutEvent next = iter.next();
+                    next.delta += ev.delta;
+                    iter.previous();
+                }
+                iter.remove();
+            }
+        }
+    }
+
+    // used for the connection window
+    int getReceiveBufferSize() {
+        return Utils.getIntegerNetProperty(
+                "sun.net.httpclient.connectionWindowSize", 256 * 1024
+        );
+    }
+
+    // returns 0 meaning block forever, or a number of millis to block for
+    synchronized long getTimeoutValue() {
+        if (timeouts.isEmpty()) {
+            return 0;
+        } else {
+            return timeouts.get(0).delta;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,367 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * Wraps socket channel layer and takes care of SSL also.
+ *
+ * Subtypes are:
+ *      PlainHttpConnection: regular direct TCP connection to server
+ *      PlainProxyConnection: plain text proxy connection
+ *      PlainTunnelingConnection: opens plain text (CONNECT) tunnel to server
+ *      SSLConnection: TLS channel direct to server
+ *      SSLTunnelConnection: TLS channel via (CONNECT) proxy tunnel
+ */
+abstract class HttpConnection implements BufferHandler {
+
+    // address we are connected to. Could be a server or a proxy
+    final InetSocketAddress address;
+    final HttpClientImpl client;
+    protected volatile ByteBuffer buffer;
+
+    HttpConnection(InetSocketAddress address, HttpClientImpl client) {
+        this.address = address;
+        this.client = client;
+    }
+
+    /**
+     * Public API to this class. addr is the ultimate destination. Any proxies
+     * etc are figured out from the request. Returns an instance of one of the
+     * following
+     *      PlainHttpConnection
+     *      PlainTunnelingConnection
+     *      SSLConnection
+     *      SSLTunnelConnection
+     *
+     * When object returned, connect() or connectAsync() must be called, which
+     * when it returns/completes, the connection is usable for requests.
+     */
+    public static HttpConnection getConnection(InetSocketAddress addr,
+                                               HttpRequestImpl request) {
+        return getConnectionImpl(addr, request);
+    }
+
+    public abstract void connect() throws IOException, InterruptedException;
+
+    public abstract CompletableFuture<Void> connectAsync();
+
+    /**
+     * Returns whether this connection is connected to its destination
+     */
+    abstract boolean connected();
+
+    abstract boolean isSecure();
+
+    abstract boolean isProxied();
+
+    /**
+     * Completes when the first byte of the response is available to be read.
+     */
+    abstract CompletableFuture<Void> whenReceivingResponse();
+
+    // must be called before reading any data off connection
+    // at beginning of response.
+    ByteBuffer getRemaining() {
+        ByteBuffer b = buffer;
+        buffer = null;
+        return b;
+    }
+
+    final boolean isOpen() {
+        return channel().isOpen();
+    }
+
+    /* Returns either a plain HTTP connection or a plain tunnelling connection
+     * for proxied websockets */
+    private static HttpConnection getPlainConnection(InetSocketAddress addr,
+                                                     InetSocketAddress proxy,
+                                                     HttpRequestImpl request) {
+        HttpClientImpl client = request.client();
+
+        if (request.isWebSocket() && proxy != null) {
+            return new PlainTunnelingConnection(addr,
+                                                proxy,
+                                                client,
+                                                request.getAccessControlContext());
+        } else {
+            if (proxy == null) {
+                return new PlainHttpConnection(addr, client);
+            } else {
+                return new PlainProxyConnection(proxy, client);
+            }
+        }
+    }
+
+    private static HttpConnection getSSLConnection(InetSocketAddress addr,
+                                                   InetSocketAddress proxy,
+                                                   HttpRequestImpl request,
+                                                   String[] alpn) {
+        HttpClientImpl client = request.client();
+        if (proxy != null) {
+            return new SSLTunnelConnection(addr,
+                                           client,
+                                           proxy,
+                                           request.getAccessControlContext());
+        } else {
+            return new SSLConnection(addr, client, alpn);
+        }
+    }
+
+    /**
+     * Main factory method.   Gets a HttpConnection, either cached or new if
+     * none available.
+     */
+    private static HttpConnection getConnectionImpl(InetSocketAddress addr,
+                                                    HttpRequestImpl request) {
+        HttpConnection c;
+        HttpClientImpl client = request.client();
+        InetSocketAddress proxy = request.proxy();
+        boolean secure = request.secure();
+        ConnectionPool pool = client.connectionPool();
+        String[] alpn =  null;
+
+        if (secure && request.requestHttp2()) {
+            alpn = new String[1];
+            alpn[0] = "h2";
+        }
+
+        if (!secure) {
+            c = pool.getConnection(false, addr, proxy);
+            if (c != null) {
+                return c;
+            } else {
+                return getPlainConnection(addr, proxy, request);
+            }
+        } else {
+            c = pool.getConnection(true, addr, proxy);
+            if (c != null) {
+                return c;
+            } else {
+                return getSSLConnection(addr, proxy, request, alpn);
+            }
+        }
+    }
+
+    void returnToCache(HttpHeaders hdrs) {
+        if (hdrs == null) {
+            // the connection was closed by server
+            close();
+            return;
+        }
+        if (!isOpen()) {
+            return;
+        }
+        ConnectionPool pool = client.connectionPool();
+        boolean keepAlive = hdrs.firstValue("Connection")
+                .map((s) -> !s.equalsIgnoreCase("close"))
+                .orElse(true);
+
+        if (keepAlive) {
+            pool.returnToPool(this);
+        } else {
+            close();
+        }
+    }
+
+    /**
+     * Also check that the number of bytes written is what was expected. This
+     * could be different if the buffer is user-supplied and its internal
+     * pointers were manipulated in a race condition.
+     */
+    final void checkWrite(long expected, ByteBuffer buffer) throws IOException {
+        long written = write(buffer);
+        if (written != expected) {
+            throw new IOException("incorrect number of bytes written");
+        }
+    }
+
+    final void checkWrite(long expected,
+                          ByteBuffer[] buffers,
+                          int start,
+                          int length)
+        throws IOException
+    {
+        long written = write(buffers, start, length);
+        if (written != expected) {
+            throw new IOException("incorrect number of bytes written");
+        }
+    }
+
+    abstract SocketChannel channel();
+
+    final InetSocketAddress address() {
+        return address;
+    }
+
+    void configureBlocking(boolean mode) throws IOException {
+        channel().configureBlocking(mode);
+    }
+
+    abstract ConnectionPool.CacheKey cacheKey();
+
+    /*
+    static PrintStream ps;
+
+    static {
+        try {
+            String propval = Utils.getNetProperty("java.net.httpclient.showData");
+            if (propval != null && propval.equalsIgnoreCase("true")) {
+                ps = new PrintStream(new FileOutputStream("/tmp/httplog.txt"), false);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    synchronized final void debugPrint(String s, ByteBuffer b) {
+        ByteBuffer[] bufs = new ByteBuffer[1];
+        bufs[0] = b;
+        debugPrint(s, bufs, 0, 1);
+    }
+
+    synchronized final void debugPrint(String s,
+                                       ByteBuffer[] bufs,
+                                       int start,
+                                       int number) {
+        if (ps == null) {
+            return;
+        }
+
+        ps.printf("\n%s:\n", s);
+
+        for (int i=start; i<start+number; i++) {
+            ByteBuffer b = bufs[i].duplicate();
+            while (b.hasRemaining()) {
+                int c = b.get();
+                if (c == 10) {
+                    ps.printf("LF \n");
+                } else if (c == 13) {
+                    ps.printf(" CR ");
+                } else if (c == 0x20) {
+                    ps.printf("_");
+                } else if (c > 0x20 && c <= 0x7F) {
+                    ps.printf("%c", (char)c);
+                } else {
+                    ps.printf("0x%02x ", c);
+                }
+            }
+        }
+        ps.printf("\n---------------------\n");
+    }
+
+    */
+
+    // overridden in SSL only
+    SSLParameters sslParameters() {
+        return null;
+    }
+
+    // Methods to be implemented for Plain TCP and SSL
+
+    abstract long write(ByteBuffer[] buffers, int start, int number)
+        throws IOException;
+
+    abstract long write(ByteBuffer buffer) throws IOException;
+
+    /**
+     * Closes this connection, by returning the socket to its connection pool.
+     */
+    abstract void close();
+
+    /**
+     * Returns a ByteBuffer with data, or null if EOF.
+     */
+    final ByteBuffer read() throws IOException {
+        return read(-1);
+    }
+
+    /**
+     * Puts position to limit and limit to capacity so we can resume reading
+     * into this buffer, but if required > 0 then limit may be reduced so that
+     * no more than required bytes are read next time.
+     */
+    static void resumeChannelRead(ByteBuffer buf, int required) {
+        int limit = buf.limit();
+        buf.position(limit);
+        int capacity = buf.capacity() - limit;
+        if (required > 0 && required < capacity) {
+            buf.limit(limit + required);
+        } else {
+            buf.limit(buf.capacity());
+        }
+    }
+
+    /**
+     * Blocks ands return requested amount.
+     */
+    final ByteBuffer read(int length) throws IOException {
+        if (length <= 0) {
+            buffer = readImpl(length);
+            return buffer;
+        }
+        buffer = readImpl(length);
+        int required = length - buffer.remaining();
+        while (buffer.remaining() < length) {
+            resumeChannelRead(buffer, required);
+            int n = readImpl(buffer);
+            required -= n;
+        }
+        return buffer;
+    }
+
+    final int read(ByteBuffer buffer) throws IOException {
+        int n = readImpl(buffer);
+        return n;
+    }
+
+    /** Reads up to length bytes. */
+    protected abstract ByteBuffer readImpl(int length) throws IOException;
+
+    /** Reads as much as possible into given buffer and returns amount read. */
+    protected abstract int readImpl(ByteBuffer buffer) throws IOException;
+
+    @Override
+    public String toString() {
+        return "HttpConnection: " + channel().toString();
+    }
+
+    @Override
+    public final ByteBuffer getBuffer() {
+        return client.getBuffer();
+    }
+
+    @Override
+    public final void returnBuffer(ByteBuffer buffer) {
+        client.returnBuffer(buffer);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeaders.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,81 @@
+/*
+ * 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.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * A read-only view of a set of received HTTP headers.
+ *
+ * @since 9
+ */
+public interface HttpHeaders {
+
+    /**
+     * Returns an {@link java.util.Optional} containing the first value of the
+     * given named (and possibly multi-valued) header. If the header is not
+     * present, then the returned {@code Optional} is empty.
+     *
+     * @param name the header name
+     * @return an {@code Optional<String>} for the first named value
+     */
+    public Optional<String> firstValue(String name);
+
+    /**
+     * Returns an {@link java.util.Optional} containing the first value of the
+     * named header field as an {@literal Optional<Long>}. If the header is not
+     * present, then the Optional is empty. If the header is present but
+     * contains a value that does not parse as a {@code Long} value, then an
+     * exception is thrown.
+     *
+     * @param name the header name
+     * @return  an {@code Optional<Long>}
+     * @throws NumberFormatException if a value is found, but does not parse as
+     *                               a Long
+     */
+    public Optional<Long> firstValueAsLong(String name);
+
+    /**
+     * Returns an unmodifiable List of all of the values of the given named
+     * header. Always returns a List, which may be empty if the header is not
+     * present.
+     *
+     * @param name the header name
+     * @return a List of String values
+     */
+    public List<String> allValues(String name);
+
+    /**
+     * Returns an unmodifiable multi Map view of this HttpHeaders. This
+     * interface should only be used when it is required to iterate over the
+     * entire set of headers.
+     *
+     * @return the Map
+     */
+    public Map<String,List<String>> map();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeaders1.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+public interface HttpHeaders1 extends HttpHeaders {
+    public void makeUnmodifiable();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,136 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Implementation of HttpHeaders.
+ */
+class HttpHeadersImpl implements HttpHeaders1 {
+
+    private final HashMap<String,List<String>> headers;
+    private boolean isUnmodifiable = false;
+
+    public HttpHeadersImpl() {
+        headers = new HashMap<>();
+    }
+
+    /**
+     * Replace all List<String> in headers with unmodifiable Lists. Call
+     * this only after all headers are added. The headers HashMap
+     * is wrapped with an unmodifiable HashMap in map()
+     */
+    @Override
+    public void makeUnmodifiable() {
+        if (isUnmodifiable)
+            return;
+
+        Set<String> keys = new HashSet<>(headers.keySet());
+        for (String key : keys) {
+            List<String> values = headers.remove(key);
+            if (values != null) {
+                headers.put(key, Collections.unmodifiableList(values));
+            }
+        }
+        isUnmodifiable = true;
+    }
+
+    @Override
+    public Optional<String> firstValue(String name) {
+        List<String> l = headers.get(name);
+        return Optional.ofNullable(l == null ? null : l.get(0));
+    }
+
+    @Override
+    public List<String> allValues(String name) {
+        return headers.get(name);
+    }
+
+    @Override
+    public Map<String, List<String>> map() {
+        return Collections.unmodifiableMap(headers);
+    }
+
+    Map<String, List<String>> directMap() {
+        return headers;
+    }
+
+    // package private mutators
+
+    public HttpHeadersImpl deepCopy() {
+        HttpHeadersImpl h1 = new HttpHeadersImpl();
+        HashMap<String,List<String>> headers1 = h1.headers;
+        Set<String> keys = headers.keySet();
+        for (String key : keys) {
+            List<String> vals = headers.get(key);
+            LinkedList<String> vals1 = new LinkedList<>(vals);
+            headers1.put(key, vals1);
+        }
+        return h1;
+    }
+
+    private List<String> getOrCreate(String name) {
+        List<String> l = headers.get(name);
+        if (l == null) {
+            l = new LinkedList<>();
+            headers.put(name, l);
+        }
+        return l;
+    }
+
+    void addHeader(String name, String value) {
+        List<String> l = getOrCreate(name);
+        l.add(value);
+    }
+
+    void setHeader(String name, String value) {
+        List<String> l = getOrCreate(name);
+        l.clear();
+        l.add(value);
+    }
+
+    @Override
+    public Optional<Long> firstValueAsLong(String name) {
+        List<String> l = headers.get(name);
+        if (l == null) {
+            return Optional.ofNullable(null);
+        } else {
+            String v = l.get(0);
+            Long lv = Long.parseLong(v);
+            return Optional.of(lv);
+        }
+    }
+
+    void clear() {
+        headers.clear();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRedirectImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,104 @@
+/*
+ * 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.*;
+
+interface HttpRedirectImpl {
+
+    static HttpRedirectImpl getRedirects(java.net.http.HttpClient.Redirect redir) {
+        switch (redir) {
+            case NEVER:
+                return HttpRedirectImpl.NEVER;
+            case ALWAYS:
+                return HttpRedirectImpl.ALWAYS;
+            case SECURE:
+                return HttpRedirectImpl.SECURE;
+            case SAME_PROTOCOL:
+                return HttpRedirectImpl.SAME_PROTOCOL;
+        }
+        return HttpRedirectImpl.NEVER;
+    }
+
+    static HttpClient.Redirect getRedirects(HttpRedirectImpl redir) {
+        if (redir == HttpRedirectImpl.NEVER) {
+            return HttpClient.Redirect.NEVER;
+        } else if (redir == HttpRedirectImpl.ALWAYS) {
+            return HttpClient.Redirect.ALWAYS;
+        } else if (redir == HttpRedirectImpl.SECURE) {
+            return HttpClient.Redirect.SECURE;
+        } else {
+            return HttpClient.Redirect.SAME_PROTOCOL;
+        }
+    }
+
+    /**
+     * Called to determine whether the given intermediate response
+     * with a redirection response code should be redirected. The target URI
+     * can be obtained from the "Location" header in the given response object.
+     *
+     * @param rsp the response from the redirected resource
+     * @return {@code true} if the redirect should be attempted automatically
+     * or {@code false} if not.
+     */
+    boolean redirect(HttpResponse rsp);
+
+    /**
+     * Never redirect.
+     */
+    static HttpRedirectImpl NEVER = (HttpResponse rsp) -> false;
+
+    /**
+     * Always redirect.
+     */
+    static HttpRedirectImpl ALWAYS = (HttpResponse rsp) -> true;
+
+    /**
+     * Redirect to same protocol only. Redirection may occur from HTTP URLs to
+     * other THHP URLs and from HTTPS URLs to other HTTPS URLs.
+     */
+    static HttpRedirectImpl SAME_PROTOCOL = (HttpResponse rsp) -> {
+        String orig = rsp.request().uri().getScheme().toLowerCase();
+        String redirect = URI.create(
+                rsp.headers().firstValue("Location").orElse(""))
+                .getScheme().toLowerCase();
+        return orig.equals(redirect);
+    };
+
+    /**
+     * Redirect always except from HTTPS URLs to HTTP URLs.
+     */
+    static HttpRedirectImpl SECURE = (HttpResponse rsp) -> {
+        String orig = rsp.request().uri().getScheme().toLowerCase();
+        String redirect = URI.create(
+                rsp.headers().firstValue("Location").orElse(""))
+                .getScheme().toLowerCase();
+        if (orig.equals("https")) {
+            return redirect.equals("https");
+        }
+        return true;
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,871 @@
+/*
+ * 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.io.InputStream;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.ProxySelector;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.*;
+import java.nio.file.Path;
+import java.util.Iterator;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.LongConsumer;
+
+/**
+ * Represents one HTTP request which can be sent to a server. {@code
+ * HttpRequest}s are built from {@code HttpRequest} {@link HttpRequest.Builder
+ * builder}s. {@code HttpRequest} builders are obtained from a {@link HttpClient}
+ * by calling {@link HttpClient#request(java.net.URI) HttpClient.request}, or
+ * by calling {@link #create(java.net.URI) HttpRequest.create} which returns a
+ * builder on the <a href="HttpClient.html#defaultclient">default</a> client.
+ * A request's {@link java.net.URI}, headers and body can be set. Request bodies
+ * are provided through a {@link BodyProcessor} object. Once all required
+ * parameters have been set in the builder, one of the builder methods should be
+ * called, which sets the request method and returns a {@code HttpRequest}.
+ * These methods are {@link Builder#GET() GET}, {@link HttpRequest.Builder#POST()
+ * POST} and {@link HttpRequest.Builder#PUT() PUT} which return a GET, POST or
+ * PUT request respectively. Alternatively, {@link
+ * HttpRequest.Builder#method(String) method} can be called to set an arbitrary
+ * method type (and return a {@code HttpRequest}). Builders can also be copied
+ * and modified multiple times in order to build multiple related requests that
+ * differ in some parameters.
+ *
+ * <p> Two simple, example HTTP interactions are shown below:
+ * <pre>
+ * {@code
+ *      // GET
+ *      HttpResponse response = HttpRequest
+ *          .create(new URI("http://www.foo.com"))
+ *          .headers("Foo", "foovalue", "Bar", "barvalue")
+ *          .GET()
+ *          .response();
+ *
+ *      int statusCode = response.statusCode();
+ *      String responseBody = response.body(asString());
+ *
+ *      // POST
+ *      response = HttpRequest
+ *          .create(new URI("http://www.foo.com"))
+ *          .body(fromString("param1=foo,param2=bar"))
+ *          .POST()
+ *          .response();}
+ * </pre>
+ *
+ * <p> The request is sent and the response obtained by calling one of the
+ * following methods.
+ * <ul><li>{@link #response() response} blocks until the entire request has been
+ * sent and the response status code and headers have been received.</li>
+ * <li>{@link #responseAsync() responseAsync} sends the request and receives the
+ * response asynchronously. Returns immediately with a
+ * {@link java.util.concurrent.CompletableFuture CompletableFuture}&lt;{@link
+ * HttpResponse}&gt;.</li>
+ * <li>{@link #multiResponseAsync(HttpResponse.MultiProcessor) multiResponseAsync}
+ * sends the request asynchronously, expecting multiple responses. This
+ * capability is of most relevance to HTTP/2 server push, but can be used for
+ * single responses (HTTP/1.1 or HTTP/2) also.</li>
+ * </ul>
+ *
+ * <p> Once a request has been sent, it is an error to try and send it again.
+ *
+ * <p> Once a {@code HttpResponse} is received, the headers and response code are
+ * available. The body can then be received by calling one of the body methods
+ * on {@code HttpResponse}.
+ *
+ * <p> See below for discussion of synchronous versus asynchronous usage.
+ *
+ * <p> <b>Request bodies</b>
+ *
+ * <p> Request bodies are sent using one of the request processor implementations
+ * below provided in {@code HttpRequest}, or else a custom implementation can be
+ * used.
+ * <ul>
+ * <li>{@link #fromByteArray(byte[]) } from byte array</li>
+ * <li>{@link #fromByteArrays(java.util.Iterator) fromByteArrays(Iterator)}
+ *      from an iterator of byte arrays</li>
+ * <li>{@link #fromFile(java.nio.file.Path) fromFile(Path)} from the file located
+ *     at the given Path</li>
+ * <li>{@link #fromString(java.lang.String) fromString(String)} from a String </li>
+ * <li>{@link #fromInputStream(java.io.InputStream) fromInputStream(InputStream)}
+ *      request body from InputStream</li>
+ * <li>{@link #noBody() } no request body is sent</li>
+ * </ul>
+ *
+ * <p> <b>Response bodies</b>
+ *
+ * <p> Responses bodies are handled by the {@link HttpResponse.BodyProcessor}
+ * {@code <T>} supplied to the {@link HttpResponse#body(HttpResponse.BodyProcessor)
+ * HttpResponse.body} and {@link HttpResponse#bodyAsync(HttpResponse.BodyProcessor)
+ * HttpResponse.bodyAsync} methods. Some implementations of {@code
+ * HttpResponse.BodyProcessor} are provided in {@link HttpResponse}:
+ * <ul>
+ * <li>{@link HttpResponse#asByteArray() } stores the body in a byte array</li>
+ * <li>{@link HttpResponse#asString()} stores the body as a String </li>
+ * <li>{@link HttpResponse#asFile(java.nio.file.Path) } stores the body in a
+ * named file</li>
+ * <li>{@link HttpResponse#ignoreBody() } ignores any received response body</li>
+ * </ul>
+ *
+ * <p> The output of a response processor is the response body, and its
+ * parameterized type {@code T} determines the type of the body object returned
+ * from {@code HttpResponse.body} and {@code HttpResponse.bodyAsync}. Therefore,
+ * as an example, the second response processor in the list above has the type
+ * {@code HttpResponse.BodyProcessor<String>} which means the type returned by
+ * {@code HttpResponse.body()} is a String. Response processors can be defined
+ * to return potentially any type as body.
+ *
+ * <p> <b>Multi responses</b>
+ *
+ * <p> With HTTP/2 it is possible for a server to return a main response and zero
+ * or more additional responses (known as server pushes) to a client-initiated
+ * request. These are handled using a special response processor called {@link
+ * HttpResponse.MultiProcessor}.
+ *
+ * <p> <b>Blocking/asynchronous behavior and thread usage</b>
+ *
+ * <p> There are two styles of request sending: <i>synchronous</i> and
+ * <i>asynchronous</i>. {@link #response() response} blocks the calling thread
+ * until the request has been sent and the response received.
+ *
+ * <p> {@link #responseAsync() responseAsync} is asynchronous and returns
+ * immediately with a {@link java.util.concurrent.CompletableFuture}&lt;{@link
+ * HttpResponse}&gt; and when this object completes (in a background thread) the
+ * response has been received.
+ *
+ * <p> {@link #multiResponseAsync(HttpResponse.MultiProcessor) multiResponseAsync}
+ * is the variant for multi responses and is also asynchronous.
+ *
+ * <p> CompletableFutures can be combined in different ways to declare the
+ * dependencies among several asynchronous tasks, while allowing for the maximum
+ * level of parallelism to be utilized.
+ *
+ * <p> <b>Security checks</b>
+ *
+ * <p> If a security manager is present then security checks are performed by
+ * the {@link #response() } and {@link #responseAsync() } methods. A {@link
+ * java.net.URLPermission} or {@link java.net.SocketPermission} is required to
+ * access any destination origin server and proxy server utilised. URLPermissions
+ * should be preferred in policy files over SocketPermissions given the more
+ * limited scope of URLPermission. Permission is always implicitly granted to a
+ * system's default proxies. The URLPermission form used to access proxies uses
+ * a method parameter of "CONNECT" (for all kinds of proxying) and a url string
+ * of the form "socket://host:port" where host and port specify the proxy's
+ * address.
+ *
+ * <p> <b>Examples</b>
+ * <pre>
+ *     import static java.net.http.HttpRequest.*;
+ *     import static java.net.http.HttpResponse.*;
+ *
+ *     //Simple blocking
+ *
+ *     HttpResponse r1 = HttpRequest.create(new URI("http://www.foo.com/"))
+ *                                  .GET()
+ *                                 .response();
+ *     int responseCode = r1.statusCode());
+ *     String body = r1.body(asString());
+ *
+ *     HttpResponse r2 = HttpRequest.create(new URI("http://www.foo.com/"))
+ *                                  .GET()
+ *                                  .response();
+ *
+ *     System.out.println("Response was " + r1.statusCode());
+ *     Path body1 = r2.body(asFile(Paths.get("/tmp/response.txt")));
+ *     // Content stored in /tmp/response.txt
+ *
+ *     HttpResponse r3 = HttpRequest.create(new URI("http://www.foo.com/"))
+ *                                  .body(fromString("param1=1, param2=2"))
+ *                                  .POST()
+ *                                  .response();
+ *
+ *     Void body2 = r3.body(ignoreBody()); // body is Void in this case
+ * </pre>
+ *
+ * <p><b>Asynchronous Example</b>
+ *
+ * <p> All of the above examples will work asynchronously, if {@link
+ * #responseAsync()} is used instead of {@link #response()} in which case the
+ * returned object is a {@code CompletableFuture<HttpResponse>} instead of
+ * {@code HttpResponse}. The following example shows how multiple requests can
+ * be sent asynchronously. It also shows how dependent asynchronous operations
+ * (receiving response, and receiving response body) can be chained easily using
+ * one of the many methods in {@code CompletableFuture}.
+ * <pre>
+ * {@code
+ *      // fetch a list of target URIs asynchronously and store them in Files.
+ *
+ *      List<URI> targets = ...
+ *
+ *      List<CompletableFuture<File>> futures = targets
+ *          .stream()
+ *          .map(target -> {
+ *              return HttpRequest
+ *                  .create(target)
+ *                  .GET()
+ *                  .responseAsync()
+ *                  .thenCompose(response -> {
+ *                      Path dest = Paths.get("base", target.getPath());
+ *                      if (response.statusCode() == 200) {
+ *                          return response.bodyAsync(asFile(dest));
+ *                      } else {
+ *                          return CompletableFuture.completedFuture(dest);
+ *                      }
+ *                  })
+ *                  // convert Path -> File
+ *                  .thenApply((Path dest) -> {
+ *                      return dest.toFile();
+ *                  });
+ *              })
+ *          .collect(Collectors.toList());
+ *
+ *      // all async operations waited for here
+ *
+ *      CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0]))
+ *          .join();
+ *
+ *      // all elements of futures have completed and can be examined.
+ *      // Use File.exists() to check whether file was successfully downloaded
+ * }
+ * </pre>
+ *
+ * @since 9
+ */
+public abstract class HttpRequest {
+
+    HttpRequest() {}
+
+    /**
+     * A builder of {@link HttpRequest}s. {@code HttpRequest.Builder}s are
+     * created by calling {@link HttpRequest#create(URI)} or {@link
+     * HttpClient#request(URI)}.
+     *
+     * <p> Each of the setter methods in this class modifies the state of the
+     * builder and returns <i>this</i> (ie. the same instance). The methods are
+     * not synchronized and should not be called from multiple threads without
+     * external synchronization.
+     *
+     * <p> The build methods return a new {@code HttpRequest} each time they are
+     * called.
+     *
+     * @since 9
+     */
+    public abstract static class Builder {
+
+        Builder() {}
+
+        /**
+         * Sets this HttpRequest's request URI.
+         *
+         * @param uri the request URI
+         * @return this request builder
+         */
+        public abstract Builder uri(URI uri);
+
+        /**
+         * Specifies whether this request will automatically follow redirects
+         * issued by the server. The default value for this setting is the value
+         * of {@link HttpClient#followRedirects() }
+         *
+         * @param policy the redirection policy
+         * @return this request builder
+         */
+        public abstract Builder followRedirects(HttpClient.Redirect policy);
+
+        /**
+         * Request server to acknowledge request before sending request
+         * body. This is disabled by default. If enabled, the server is requested
+         * to send an error response or a 100-Continue response before the client
+         * sends the request body. This means the request processor for the
+         * request will not be invoked until this interim response is received.
+         *
+         * @param enable {@code true} if Expect continue to be sent
+         * @return this request builder
+         */
+        public abstract Builder expectContinue(boolean enable);
+
+        /**
+         * Overrides the {@link HttpClient#version()  } setting for this
+         * request.
+         *
+         * @param version the HTTP protocol version requested
+         * @return this request builder
+         */
+        public abstract Builder version(HttpClient.Version version);
+
+        /**
+         * Adds the given name value pair to the set of headers for this request.
+         *
+         * @param name the header name
+         * @param value the header value
+         * @return this request builder
+         */
+        public abstract Builder header(String name, String value);
+
+        /**
+         * Overrides the ProxySelector set on the request's client for this
+         * request.
+         *
+         * @param proxy the ProxySelector to use
+         * @return this request builder
+         */
+        public abstract Builder proxy(ProxySelector proxy);
+
+        /**
+         * Adds the given name value pairs to the set of headers for this
+         * request. The supplied Strings must alternate as names and values.
+         *
+         * @param headers the list of String name value pairs
+         * @return this request builder
+         * @throws IllegalArgumentException if there is an odd number of
+         *                                  parameters
+         */
+        public abstract Builder headers(String... headers);
+
+        /**
+         * Sets a timeout for this request. If the response is not received
+         * within the specified timeout then a {@link HttpTimeoutException} is
+         * thrown from {@link #response() } or {@link #responseAsync() }
+         * completes exceptionally with a {@code HttpTimeoutException}.
+         *
+         * @param unit the timeout units
+         * @param timeval the number of units to wait for
+         * @return this request builder
+         */
+        public abstract Builder timeout(TimeUnit unit, long timeval);
+
+        /**
+         * Sets the given name value pair to the set of headers for this
+         * request. This overwrites any previously set values for name.
+         *
+         * @param name the header name
+         * @param value the header value
+         * @return this request builder
+         */
+        public abstract Builder setHeader(String name, String value);
+
+        /**
+         * Sets a request body for this builder. See {@link HttpRequest}
+         * for example {@code BodyProcessor} implementations.
+         * If no body is specified, then no body is sent with the request.
+         *
+         * @param reqproc the request body processor
+         * @return this request builder
+         */
+        public abstract Builder body(BodyProcessor reqproc);
+
+        /**
+         * Builds and returns a GET {@link HttpRequest} from this builder.
+         *
+         * @return a {@code HttpRequest}
+         */
+        public abstract HttpRequest GET();
+
+        /**
+         * Builds and returns a POST {@link HttpRequest} from this builder.
+         *
+         * @return a {@code HttpRequest}
+         */
+        public abstract HttpRequest POST();
+
+        /**
+         * Builds and returns a PUT {@link HttpRequest} from this builder.
+         *
+         * @return a {@code HttpRequest}
+         */
+        public abstract HttpRequest PUT();
+
+        /**
+         * Builds and returns a {@link HttpRequest} from this builder using
+         * the given method String. The method string is case-sensitive, and
+         * may be rejected if an upper-case string is not used.
+         *
+         * @param method the method to use
+         * @return a {@code HttpRequest}
+         * @throws IllegalArgumentException if an unrecognised method is used
+         */
+        public abstract HttpRequest method(String method);
+
+        /**
+         * Returns an exact duplicate copy of this Builder based on current
+         * state. The new builder can then be modified independently of this
+         * builder.
+         *
+         * @return an exact copy of this Builder
+         */
+        public abstract Builder copy();
+    }
+
+    /**
+     * Creates a HttpRequest builder from the <i>default</i> HttpClient.
+     *
+     * @param uri the request URI
+     * @return a new request builder
+     */
+    public static HttpRequest.Builder create(URI uri) {
+        return HttpClient.getDefault().request(uri);
+    }
+
+    /**
+     * Returns the follow-redirects setting for this request.
+     *
+     * @return follow redirects setting
+     */
+    public abstract HttpClient.Redirect followRedirects();
+
+    /**
+     * Returns the response to this request, by sending it and blocking if
+     * necessary to get the response. The {@link HttpResponse} contains the
+     * response status and headers.
+     *
+     * @return a HttpResponse for this request
+     * @throws IOException if an I/O error occurs
+     * @throws InterruptedException if the operation was interrupted
+     * @throws SecurityException if the caller does not have the required
+     *                           permission
+     * @throws IllegalStateException if called more than once or if
+     *                               responseAsync() called previously
+     */
+    public abstract HttpResponse response()
+        throws IOException, InterruptedException;
+
+    /**
+     * Sends the request and returns the response asynchronously. This method
+     * returns immediately with a {@link CompletableFuture}&lt;{@link
+     * HttpResponse}&gt;
+     *
+     * @return a {@code CompletableFuture<HttpResponse>}
+     * @throws IllegalStateException if called more than once or if response()
+     *                               called previously.
+     */
+    public abstract CompletableFuture<HttpResponse> responseAsync();
+
+    /**
+     * Sends the request asynchronously expecting multiple responses.
+     *
+     * <p> This method must be given a {@link HttpResponse.MultiProcessor} to
+     * handle the multiple responses.
+     *
+     * <p> If a security manager is set, the caller must possess a {@link
+     * java.net.URLPermission} for the request's URI, method and any user set
+     * headers. The security manager is also checked for each incoming
+     * additional server generated request/response. Any request that fails the
+     * security check, is canceled and ignored.
+     *
+     * <p> This method can be used for both HTTP/1.1 and HTTP/2, but in cases
+     * where multiple responses are not supported, the MultiProcessor
+     * only receives the main response.
+     *
+     * <p> The aggregate {@code CompletableFuture} returned from this method
+     * returns a {@code <U>} defined by the {@link HttpResponse.MultiProcessor}
+     * implementation supplied. This will typically be a Collection of
+     * HttpResponses or of some response body type.
+     *
+     * @param <U> the aggregate response type
+     * @param rspproc the MultiProcessor for the request
+     * @return a {@code CompletableFuture<U>}
+     * @throws IllegalStateException if the request has already been sent.
+     */
+    public abstract <U> CompletableFuture<U>
+    multiResponseAsync(HttpResponse.MultiProcessor<U> rspproc);
+
+    /**
+     * Returns the request method for this request. If not set explicitly,
+     * the default method for any request is "GET".
+     *
+     * @return this request's method
+     */
+    public abstract String method();
+
+    /**
+     * Returns this request's {@link HttpRequest.Builder#expectContinue(boolean)
+     * expect continue } setting.
+     *
+     * @return this request's expect continue setting
+     */
+    public abstract boolean expectContinue();
+
+    /**
+     * Returns this request's request URI.
+     *
+     * @return this request's URI
+     */
+    public abstract URI uri();
+
+    /**
+     * Returns this request's {@link HttpClient}.
+     *
+     * @return this request's HttpClient
+     */
+    public abstract HttpClient client();
+
+    /**
+     * Returns the HTTP protocol version that this request will use or used.
+     *
+     * @return HTTP protocol version
+     */
+    public abstract HttpClient.Version version();
+
+    /**
+     * The (user-accessible) request headers that this request was (or will be)
+     * sent with.
+     *
+     * @return this request's HttpHeaders
+     */
+    public abstract HttpHeaders headers();
+
+    /**
+     * Returns a request processor whose body is the given String, converted
+     * using the {@link java.nio.charset.StandardCharsets#ISO_8859_1 ISO_8859_1}
+     * character set.
+     *
+     * @param body the String containing the body
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromString(String body) {
+        return fromString(body, StandardCharsets.ISO_8859_1);
+    }
+
+    /**
+     * A request processor that takes data from the contents of a File.
+     *
+     * @param path the path to the file containing the body
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromFile(Path path) {
+        FileChannel fc;
+        long size;
+
+        try {
+            fc = FileChannel.open(path);
+            size = fc.size();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+
+        return new BodyProcessor() {
+            LongConsumer flow;
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                // could return exact file length, but for now -1
+                this.flow = flow;
+                flow.accept(1);
+                if (size != 0) {
+                    return size;
+                } else {
+                    return -1;
+                }
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer) throws IOException {
+                int n = fc.read(buffer);
+                if (n == -1) {
+                    fc.close();
+                    return true;
+                }
+                flow.accept(1);
+                return false;
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                try {
+                    fc.close();
+                } catch (IOException ex) {
+                    Log.logError(ex.toString());
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns a request processor whose body is the given String, converted
+     * using the given character set.
+     *
+     * @param s the String containing the body
+     * @param charset the character set to convert the string to bytes
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromString(String s, Charset charset) {
+        return fromByteArray(s.getBytes(charset));
+    }
+
+    /**
+     * Returns a request processor whose body is the given byte array.
+     *
+     * @param buf the byte array containing the body
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromByteArray(byte[] buf) {
+        return fromByteArray(buf, 0, buf.length);
+    }
+
+    /**
+     * Returns a request processor whose body is the content of the given byte
+     * array length bytes starting from the specified offset.
+     *
+     * @param buf the byte array containing the body
+     * @param offset the offset of the first byte
+     * @param length the number of bytes to use
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromByteArray(byte[] buf, int offset, int length) {
+
+        return new BodyProcessor() {
+            LongConsumer flow;
+            byte[] barray;
+            int index;
+            int sent;
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                this.flow = flow;
+                flow.accept(1);
+                barray = buf;
+                index = offset;
+                return length;
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer)
+                throws IOException
+            {
+                if (sent == length) {
+                    return true;
+                }
+
+                int remaining = buffer.remaining();
+                int left = length - sent;
+                int n = remaining > left ? left : remaining;
+                buffer.put(barray, index, n);
+                index += n;
+                sent += n;
+                flow.accept(1);
+                return sent == length;
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                Log.logError(t.toString());
+            }
+        };
+    }
+
+    /**
+     * A request processor that takes data from an Iterator of byte arrays.
+     *
+     * @param iter an Iterator of byte arrays
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromByteArrays(Iterator<byte[]> iter) {
+
+        return new BodyProcessor() {
+            LongConsumer flow;
+            byte[] current;
+            int curIndex;
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                this.flow = flow;
+                flow.accept(1);
+                return -1;
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer)
+                throws IOException
+            {
+                int remaining;
+
+                while ((remaining = buffer.remaining()) > 0) {
+                    if (current == null) {
+                        if (!iter.hasNext()) {
+                            return true;
+                        }
+                        current = iter.next();
+                        curIndex = 0;
+                    }
+                    int n = Math.min(remaining, current.length - curIndex);
+                    buffer.put(current, curIndex, n);
+                    curIndex += n;
+
+                    if (curIndex == current.length) {
+                        current = null;
+                        flow.accept(1);
+                        return false;
+                    }
+                }
+                flow.accept(1);
+                return false;
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                Log.logError(t.toString());
+            }
+        };
+    }
+
+    /**
+     * A request processor that reads its data from an InputStream.
+     *
+     * @param stream an InputStream
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromInputStream(InputStream stream) {
+        // for now, this blocks. It could be offloaded to a separate thread
+        // to do reading and guarantee that onRequestBodyChunk() won't block
+        return new BodyProcessor() {
+            LongConsumer flow;
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                this.flow = flow;
+                flow.accept(1);
+                return -1;
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer)
+                throws IOException
+            {
+                int remaining = buffer.remaining();
+                int n = stream.read(buffer.array(), buffer.arrayOffset(), remaining);
+                if (n == -1) {
+                    stream.close();
+                    return true;
+                }
+                buffer.position(buffer.position() + n);
+                flow.accept(1);
+                return false;
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                Log.logError(t.toString());
+            }
+        };
+    }
+
+    /**
+     * A request processor which sends no request body.
+     *
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor noBody() {
+        return new BodyProcessor() {
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                return 0;
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer)
+                throws IOException
+            {
+                throw new InternalError("should never reach here");
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                Log.logError(t.toString());
+            }
+        };
+    }
+
+    /**
+     * A request processor which obtains the request body from some source.
+     * Implementations of this interface are provided which allow request bodies
+     * to be supplied from standard types, such as {@code String, byte[], File,
+     * InputStream}. Other implementations can be provided.
+     *
+     * <p> The methods of this interface may be called from multiple threads,
+     * but only one method is invoked at a time, and behaves as if called from
+     * one thread.
+     *
+     * <p> See {@link HttpRequest} for implementations that take request bodies
+     * from {@code byte arrays, Strings, Paths} etc.
+     *
+     * @since 9
+     */
+    public interface BodyProcessor {
+
+        /**
+         * Called before a request is sent. Is expected to return the content
+         * length of the request body. Zero means no content. Less than zero
+         * means an unknown positive content-length, and the body will be
+         * streamed.
+         *
+         * <p> The flowController object must be used to manage the flow of
+         * calls to {@link #onRequestBodyChunk(ByteBuffer)}. The typical usage
+         * for a non-blocking processor is to call it once inside
+         * onRequestStart() and once during each call to onRequestBodyChunk().
+         *
+         * @param hr the request
+         * @param flowController the HttpFlowController
+         * @return the content length
+         * @throws IOException if an I/O error occurs
+         */
+        long onRequestStart(HttpRequest hr, LongConsumer flowController)
+            throws IOException;
+
+        /**
+         * Called if sending a request body fails.
+         *
+         * @implSpec The default implementation does nothing.
+         *
+         * @param t the Throwable that caused the failure
+         */
+        default void onRequestError(Throwable t) { }
+
+        /**
+         * Called to obtain a buffer of data to send. The data must be placed
+         * in the provided buffer. The implementation should not block. The
+         * boolean return code notifies the protocol implementation if the
+         * supplied buffer is the final one (or not).
+         *
+         * @param buffer a ByteBuffer to write data into
+         * @return whether or not this is the last buffer
+         * @throws IOException if an I/O error occurs
+         */
+        boolean onRequestBodyChunk(ByteBuffer buffer) throws IOException;
+
+        /**
+         * Called when the request body has been completely sent.
+         *
+         * @implSpec The default implementation does nothing
+         */
+        default void onComplete() {
+            // TODO: need to call this
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,177 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.net.URI;
+import java.net.ProxySelector;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+class HttpRequestBuilderImpl extends HttpRequest.Builder {
+
+    private HttpHeadersImpl userHeaders;
+    private URI uri;
+    private String method;
+    private HttpClient.Redirect followRedirects;
+    private boolean expectContinue;
+    private HttpRequest.BodyProcessor body;
+    private HttpClient.Version version;
+    private final HttpClientImpl client;
+    private ProxySelector proxy;
+    private long timeval = 0;
+
+    public HttpRequestBuilderImpl(HttpClientImpl client, URI uri) {
+        this.client = client;
+        this.uri = uri;
+        this.version = client.version();
+        this.userHeaders = new HttpHeadersImpl();
+    }
+
+    @Override
+    public HttpRequestBuilderImpl body(HttpRequest.BodyProcessor reqproc) {
+        Objects.requireNonNull(reqproc);
+        this.body = reqproc;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl uri(URI uri) {
+        Objects.requireNonNull(uri);
+        this.uri = uri;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl followRedirects(HttpClient.Redirect follow) {
+        Objects.requireNonNull(follow);
+        this.followRedirects = follow;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl header(String name, String value) {
+        Objects.requireNonNull(name);
+        Objects.requireNonNull(value);
+        Utils.validateToken(name, "invalid header name");
+        userHeaders.addHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl headers(String... params) {
+        Objects.requireNonNull(params);
+        if (params.length % 2 != 0) {
+            throw new IllegalArgumentException("wrong number of parameters");
+        }
+        for (int i=0; i<params.length; ) {
+            String name = params[i];
+            String value = params[i+1];
+            header(name, value);
+            i+=2;
+        }
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl proxy(ProxySelector proxy) {
+        Objects.requireNonNull(proxy);
+        this.proxy = proxy;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl copy() {
+        HttpRequestBuilderImpl b = new HttpRequestBuilderImpl(this.client, this.uri);
+        b.userHeaders = this.userHeaders.deepCopy();
+        b.method = this.method;
+        b.followRedirects = this.followRedirects;
+        b.expectContinue = this.expectContinue;
+        b.body = body;
+        b.uri = uri;
+        b.proxy = proxy;
+        return b;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl setHeader(String name, String value) {
+        Objects.requireNonNull(name);
+        Objects.requireNonNull(value);
+        userHeaders.setHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl expectContinue(boolean enable) {
+        expectContinue = enable;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl version(HttpClient.Version version) {
+        Objects.requireNonNull(version);
+        this.version = version;
+        return this;
+    }
+
+    HttpHeadersImpl headers() {  return userHeaders; }
+
+    URI uri() { return uri; }
+
+    String method() { return method; }
+
+    HttpClient.Redirect followRedirects() { return followRedirects; }
+
+    ProxySelector proxy() { return proxy; }
+
+    boolean expectContinue() { return expectContinue; }
+
+    HttpRequest.BodyProcessor body() { return body; }
+
+    HttpClient.Version version() { return version; }
+
+    @Override
+    public HttpRequest GET() { return method("GET"); }
+
+    @Override
+    public HttpRequest POST() { return method("POST"); }
+
+    @Override
+    public HttpRequest PUT() { return method("PUT"); }
+
+    @Override
+    public HttpRequest method(String method) {
+        Objects.requireNonNull(method);
+        this.method = method;
+        return new HttpRequestImpl(client, method, this);
+    }
+
+    @Override
+    public HttpRequest.Builder timeout(TimeUnit timeunit, long timeval) {
+        Objects.requireNonNull(timeunit);
+        this.timeval = timeunit.toMillis(timeval);
+        return this;
+    }
+
+    long timeval() { return timeval; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,285 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.net.http.HttpClient.Version;
+import java.net.http.HttpResponse.MultiProcessor;
+import java.util.concurrent.CompletableFuture;
+import java.net.SocketPermission;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.Set;
+import static java.net.http.HttpRedirectImpl.getRedirects;
+import java.util.Locale;
+
+class HttpRequestImpl extends HttpRequest {
+
+    private final HttpHeadersImpl userHeaders;
+    private final HttpHeadersImpl systemHeaders;
+    private final URI uri;
+    private InetSocketAddress authority; // only used when URI not specified
+    private final String method;
+    private final HttpClientImpl client;
+    private final HttpRedirectImpl followRedirects;
+    private final ProxySelector proxy;
+    final BodyProcessor requestProcessor;
+    final boolean secure;
+    final boolean expectContinue;
+    private final java.net.http.HttpClient.Version version;
+    private boolean isWebSocket;
+    final MultiExchange exchange;
+    private boolean receiving;
+    private AccessControlContext acc;
+    private final long timeval;
+
+    public HttpRequestImpl(HttpClientImpl client,
+                           String method,
+                           HttpRequestBuilderImpl builder) {
+        this.client = client;
+        this.method = method == null? "GET" : method;
+        this.userHeaders = builder.headers() == null ?
+                new HttpHeadersImpl() : builder.headers();
+        dropDisallowedHeaders();
+        this.followRedirects = getRedirects(builder.followRedirects() == null ?
+                client.followRedirects() : builder.followRedirects());
+        this.systemHeaders = new HttpHeadersImpl();
+        this.uri = builder.uri();
+        this.proxy = builder.proxy();
+        this.expectContinue = builder.expectContinue();
+        this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
+        this.version = builder.version();
+        if (builder.body() == null) {
+            this.requestProcessor = HttpRequest.noBody();
+        } else {
+            this.requestProcessor = builder.body();
+        }
+        this.exchange = new MultiExchange(this);
+        this.timeval = builder.timeval();
+    }
+
+    /** Creates a HttpRequestImpl using fields of an existing request impl. */
+    public HttpRequestImpl(URI uri,
+                           HttpRequest request,
+                           HttpClientImpl client,
+                           String method,
+                           HttpRequestImpl other) {
+        this.client = client;
+        this.method = method == null? "GET" : method;
+        this.userHeaders = other.userHeaders == null ?
+                new HttpHeadersImpl() : other.userHeaders;
+        dropDisallowedHeaders();
+        this.followRedirects = getRedirects(other.followRedirects() == null ?
+                client.followRedirects() : other.followRedirects());
+        this.systemHeaders = other.systemHeaders;
+        this.uri = uri;
+        this.expectContinue = other.expectContinue;
+        this.secure = other.secure;
+        this.requestProcessor = other.requestProcessor;
+        this.proxy = other.proxy;
+        this.version = other.version;
+        this.acc = other.acc;
+        this.exchange = new MultiExchange(this);
+        this.timeval = other.timeval;
+    }
+
+    /* used for creating CONNECT requests  */
+    HttpRequestImpl(HttpClientImpl client,
+                    String method,
+                    InetSocketAddress authority) {
+        this.client = client;
+        this.method = method;
+        this.followRedirects = getRedirects(client.followRedirects());
+        this.systemHeaders = new HttpHeadersImpl();
+        this.userHeaders = new HttpHeadersImpl();
+        this.uri = null;
+        this.proxy = null;
+        this.requestProcessor = HttpRequest.noBody();
+        this.version = java.net.http.HttpClient.Version.HTTP_1_1;
+        this.authority = authority;
+        this.secure = false;
+        this.expectContinue = false;
+        this.exchange = new MultiExchange(this);
+        this.timeval = 0; // block TODO: fix
+    }
+
+    @Override
+    public HttpClientImpl client() {
+        return client;
+    }
+
+
+    @Override
+    public String toString() {
+        return (uri == null ? "" : uri.toString()) + "/" + method + "("
+                + hashCode() + ")";
+    }
+
+    @Override
+    public HttpHeaders headers() {
+        userHeaders.makeUnmodifiable();
+        return userHeaders;
+    }
+
+    InetSocketAddress authority() { return authority; }
+
+    void setH2Upgrade() {
+        Http2ClientImpl h2client = client.client2();
+        systemHeaders.setHeader("Connection", "Upgrade, HTTP2-Settings");
+        systemHeaders.setHeader("Upgrade", "h2c");
+        systemHeaders.setHeader("HTTP2-Settings", h2client.getSettingsString());
+    }
+
+    private static final Set<String>  DISALLOWED_HEADERS_SET = Set.of(
+        "authorization", "connection", "cookie", "content-length",
+        "date", "expect", "from", "host", "origin", "proxy-authorization",
+        "referer", "user-agent", "upgrade", "via", "warning");
+
+
+    // we silently drop headers that are disallowed
+    private void dropDisallowedHeaders() {
+        Set<String> hdrnames = userHeaders.directMap().keySet();
+
+        hdrnames.removeIf((s) ->
+              DISALLOWED_HEADERS_SET.contains(s.toLowerCase())
+        );
+    }
+
+    private synchronized void receiving() {
+        if (receiving) {
+            throw new IllegalStateException("already receiving response");
+        }
+        receiving = true;
+    }
+
+    /*
+     * Response filters may result in a new HttpRequestImpl being created
+     * (but still associated with the same API HttpRequest) and the process
+     * is repeated.
+     */
+    @Override
+    public HttpResponse response() throws IOException, InterruptedException {
+        receiving(); // TODO: update docs
+        if (System.getSecurityManager() != null) {
+            acc = AccessController.getContext();
+        }
+        return exchange.response();
+    }
+
+    @Override
+    public synchronized CompletableFuture<HttpResponse> responseAsync() {
+        receiving(); // TODO: update docs
+        if (System.getSecurityManager() != null) {
+            acc = AccessController.getContext();
+        }
+        return exchange.responseAsync(null)
+            .thenApply((r) -> (HttpResponse)r);
+    }
+
+    public <U> CompletableFuture<U>
+    sendAsyncMulti(HttpResponse.MultiProcessor<U> rspproc) {
+        // To change body of generated methods, choose Tools | Templates.
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public boolean expectContinue() { return expectContinue; }
+
+    public boolean requestHttp2() {
+        return version.equals(HttpClient.Version.HTTP_2);
+        //return client.getHttp2Allowed();
+    }
+
+    AccessControlContext getAccessControlContext() { return acc; }
+
+    InetSocketAddress proxy() {
+        ProxySelector ps = this.proxy;
+        if (ps == null) {
+            ps = client.proxy().orElse(null);
+        }
+        if (ps == null || method.equalsIgnoreCase("CONNECT")) {
+            return null;
+        }
+        return (InetSocketAddress)ps.select(uri).get(0).address();
+    }
+
+    boolean secure() { return secure; }
+
+    void isWebSocket(boolean is) {
+        isWebSocket = is;
+    }
+
+    boolean isWebSocket() {
+        return isWebSocket;
+    }
+
+    /** Returns the follow-redirects setting for this request. */
+    @Override
+    public java.net.http.HttpClient.Redirect followRedirects() {
+        return getRedirects(followRedirects);
+    }
+
+    HttpRedirectImpl followRedirectsImpl() { return followRedirects; }
+
+    /**
+     * Returns the request method for this request. If not set explicitly,
+     * the default method for any request is "GET".
+     */
+    @Override
+    public String method() { return method; }
+
+    @Override
+    public URI uri() { return uri; }
+
+    HttpHeadersImpl getUserHeaders() { return userHeaders; }
+
+    HttpHeadersImpl getSystemHeaders() { return systemHeaders; }
+
+    HttpClientImpl getClient() { return client; }
+
+    BodyProcessor requestProcessor() { return requestProcessor; }
+
+    @Override
+    public Version version() { return version; }
+
+    void addSystemHeader(String name, String value) {
+        systemHeaders.addHeader(name, value);
+    }
+
+    void setSystemHeader(String name, String value) {
+        systemHeaders.setHeader(name, value);
+    }
+
+    long timeval() { return timeval; }
+
+    @Override
+    public <U> CompletableFuture<U>
+    multiResponseAsync(MultiProcessor<U> rspproc) {
+        //To change body of generated methods, choose Tools | Templates.
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,977 @@
+/*
+ * 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.io.InputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * Represents a response to a {@link HttpRequest}. A {@code HttpResponse} is
+ * available when the response status code and headers have been received, but
+ * before the response body is received.
+ *
+ * <p> Methods are provided in this class for accessing the response headers,
+ * and status code immediately and also methods for retrieving the response body.
+ * Static methods are provided which implement {@link BodyProcessor} for
+ * standard body types such as {@code String, byte arrays, files}.
+ *
+ * <p> The {@link #body(BodyProcessor) body} or {@link #bodyAsync(BodyProcessor)
+ * bodyAsync} which retrieve any response body must be called to ensure that the
+ * TCP connection can be re-used subsequently, and any response trailers
+ * accessed, if they exist, unless it is known that no response body was received.
+ *
+ * @since 9
+ */
+public abstract class HttpResponse {
+
+    HttpResponse() { }
+
+    /**
+     * Returns the status code for this response.
+     *
+     * @return the response code
+     */
+    public abstract int statusCode();
+
+    /**
+     * Returns the {@link HttpRequest} for this response.
+     *
+     * @return the request
+     */
+    public abstract HttpRequest request();
+
+    /**
+     * Returns the received response headers.
+     *
+     * @return the response headers
+     */
+    public abstract HttpHeaders headers();
+
+    /**
+     * Returns the received response trailers, if there are any. This must only
+     * be called after the response body has been received.
+     *
+     * @return the response trailers (may be empty)
+     * @throws IllegalStateException if the response body has not been received
+     *                               yet
+     */
+    public abstract HttpHeaders trailers();
+
+    /**
+     * Returns the body, blocking if necessary. The type T is determined by the
+     * {@link BodyProcessor} implementation supplied. The body object will be
+     * returned immediately if it is a type (such as {@link java.io.InputStream}
+     * which reads the data itself. If the body object represents the fully read
+     * body then it blocks until it is fully read.
+     *
+     * @param <T> the type of the returned body object
+     * @param processor the processor to handle the response body
+     * @return the body
+     * @throws java.io.UncheckedIOException if an I/O error occurs reading the
+     *                                      response
+     */
+    public abstract <T> T body(BodyProcessor<T> processor);
+
+    /**
+     * Returns a {@link java.util.concurrent.CompletableFuture} of type T. This
+     * always returns immediately and the future completes when the body object
+     * is available. The body will be available immediately if it is a type
+     * (such as {@link java.io.InputStream} which reads the data itself. If the
+     * body object represents the fully read body then it will not be available
+     * until it is fully read.
+     *
+     * @param <T> the type of the returned body object
+     * @param processor the processor to handle the response body
+     * @return a CompletableFuture
+     */
+    public abstract <T> CompletableFuture<T> bodyAsync(BodyProcessor<T> processor);
+
+    /**
+     * Returns the {@link javax.net.ssl.SSLParameters} in effect for this
+     * response. Returns {@code null} if this is not a https response.
+     *
+     * @return the SSLParameters associated with the response
+     */
+    public abstract SSLParameters sslParameters();
+
+    /**
+     * Returns the URI that the response was received from. This may be
+     * different from the request URI if redirection occurred.
+     *
+     * @return the URI of the response
+     */
+    public abstract URI uri();
+
+    /**
+     * Returns the HTTP protocol version that was used for this response.
+     *
+     * @return HTTP protocol version
+     */
+    public abstract HttpClient.Version version();
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;{@link java.nio.file.Path}&gt; where
+     * the file is created if it does not already exist. When the Path object is
+     * returned, the body has been completely written to the file.
+     *
+     * @param file the file to store the body in
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Path> asFile(Path file) {
+        return asFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
+    }
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;{@link java.nio.file.Path}&gt; where
+     * the download directory is specified, but the filename is obtained from
+     * the Content-Disposition response header. The Content-Disposition header
+     * must specify the <i>attachment</i> type and must also contain a
+     * <i>filename</i> parameter. If the filename specifies multiple path
+     * components only the final component is used as the filename (with the
+     * given directory name). When the Path object is returned, the body has
+     * been completely written to the file. The returned Path is the combination
+     * of the supplied directory name and the file name supplied by the server.
+     * If the destination directory does not exist or cannot be written to, then
+     * the response will fail with an IOException.
+     *
+     * @param directory the directory to store the file in
+     * @param openOptions open options
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Path> asFileDownload(Path directory,
+                                                     OpenOption... openOptions) {
+        return new AbstractResponseProcessor<Path>() {
+
+            FileChannel fc;
+            Path file;
+
+            @Override
+            public Path onResponseBodyStartImpl(long contentLength,
+                                                HttpHeaders headers)
+                throws IOException
+            {
+                String dispoHeader = headers.firstValue("Content-Disposition")
+                        .orElseThrow(() -> new IOException("No Content-Disposition"));
+                if (!dispoHeader.startsWith("attachment;")) {
+                    throw new IOException("Unknown Content-Disposition type");
+                }
+                int n = dispoHeader.indexOf("filename=");
+                if (n == -1) {
+                    throw new IOException("Bad Content-Disposition type");
+                }
+                String disposition = dispoHeader.substring(n + 9,
+                                                           dispoHeader.lastIndexOf(';'));
+                file = Paths.get(directory.toString(), disposition);
+                fc = FileChannel.open(file, openOptions);
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b) throws IOException {
+                fc.write(b);
+            }
+
+            @Override
+            public Path onResponseComplete() throws IOException {
+                fc.close();
+                return file;
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                try {
+                    if (fc != null) {
+                        fc.close();
+                    }
+                } catch (IOException e) {
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;{@link java.nio.file.Path}&gt;.
+     *
+     * <p> {@link HttpResponse}s returned using this response processor complete
+     * after the entire response, including body has been read.
+     *
+     * @param file the filename to store the body in
+     * @param openOptions any options to use when opening/creating the file
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Path> asFile(Path file,
+                                             OpenOption... openOptions) {
+        return new AbstractResponseProcessor<Path>() {
+
+            FileChannel fc;
+
+            @Override
+            public Path onResponseBodyStartImpl(long contentLength,
+                                                HttpHeaders headers)
+                throws IOException
+            {
+                fc = FileChannel.open(file, openOptions);
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b)
+                throws IOException
+            {
+                fc.write(b);
+            }
+
+            @Override
+            public Path onResponseComplete() throws IOException {
+                fc.close();
+                return file;
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                try {
+                    if (fc != null) {
+                        fc.close();
+                    }
+                } catch (IOException e) {
+                }
+            }
+        };
+    }
+
+    static class ByteArrayResponseProcessor {
+
+        static final int INITIAL_BUFLEN = 1024;
+
+        byte[] buffer;
+        int capacity;
+        boolean knownLength;
+        int position;
+
+        ByteArrayResponseProcessor() { }
+
+        public byte[] onStart(long contentLength) throws IOException {
+            if (contentLength > Integer.MAX_VALUE) {
+                throw new IllegalArgumentException(
+                        "byte array response limited to MAX_INT size");
+            }
+            capacity = (int) contentLength;
+            if (capacity != -1) {
+                buffer = new byte[capacity];
+                knownLength = true;
+            } else {
+                buffer = new byte[INITIAL_BUFLEN];
+                capacity = INITIAL_BUFLEN;
+                knownLength = false;
+            }
+            position = 0;
+            return null;
+        }
+
+        public void onBodyContent(ByteBuffer b) throws IOException {
+            int toCopy = b.remaining();
+            int size = capacity;
+            if (toCopy > capacity - position) {
+                // resize
+                size += toCopy * 2;
+            }
+            if (size != capacity) {
+                if (knownLength) {
+                    // capacity should have been right from start
+                    throw new IOException("Inconsistent content length");
+                }
+                byte[] newbuf = new byte[size];
+                System.arraycopy(buffer, 0, newbuf, 0, position);
+                buffer = newbuf;
+                capacity = size;
+            }
+            int srcposition = b.arrayOffset() + b.position();
+            System.arraycopy(b.array(), srcposition, buffer, position, toCopy);
+            b.position(b.limit());
+            position += toCopy;
+        }
+
+        public byte[] onComplete() throws IOException {
+            if (knownLength) {
+                if (position != capacity) {
+                    throw new IOException("Wrong number of bytes received");
+                }
+                return buffer;
+            }
+            byte[] buf1 = new byte[position];
+            System.arraycopy(buffer, 0, buf1, 0, position);
+            return buf1;
+        }
+
+        public void onError(Throwable t) {
+            // TODO:
+        }
+    }
+
+    static final byte[] EMPTY = new byte[0];
+
+    /**
+     * Returns a response processor which supplies the response body to the
+     * given Consumer. Each time data is received the consumer is invoked with a
+     * byte[] containing at least one byte of data. After the final buffer is
+     * received, the consumer is invoked one last time, with an empty byte
+     * array.
+     *
+     * @param consumer a Consumer to accept the response body
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Void> asByteArrayConsumer(Consumer<byte[]> consumer) {
+        return new AbstractResponseProcessor<Void>() {
+            @Override
+            public Void onResponseBodyStartImpl(long clen,
+                                                HttpHeaders h)
+                throws IOException
+            {
+                return null;
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b) throws IOException {
+                if (!b.hasRemaining()) {
+                    return;
+                }
+                byte[] buf = new byte[b.remaining()];
+                b.get(buf);
+                consumer.accept(buf);
+            }
+
+            @Override
+            public Void onResponseComplete() throws IOException {
+                consumer.accept(EMPTY);
+                return null;
+            }
+        };
+    }
+
+    /**
+     * Returns a BodyProcessor which delivers the response data to a
+     * {@link java.util.concurrent.Flow.Subscriber}{@code ByteBuffer}.
+     * <p>
+     * The given {@code Supplier<U>} is invoked when the Flow is completed in
+     * order to convert the flow data into the U object that is returned as the
+     * response body.
+     *
+     * @param <U> the response body type
+     * @param subscriber the Flow.Subscriber
+     * @param bufferSize the maximum number of bytes of data to be supplied in
+     * each ByteBuffer
+     * @param bodySupplier an object that converts the received data to the body
+     * type U.
+     * @return a BodyProcessor
+     *
+     * public static <U> BodyProcessor<Flow.Subscriber<ByteBuffer>>
+     * asFlowSubscriber() {
+     *
+     * return new BodyProcessor<U>() { Flow.Subscriber<ByteBuffer> subscriber;
+     * LongConsumer flowController; FlowSubscription subscription; Supplier<U>
+     * bodySupplier; int bufferSize; // down-stream Flow window. long
+     * buffersWindow; // upstream window long bytesWindow;
+     * LinkedList<ByteBuffer> buffers = new LinkedList<>();
+     *
+     * class FlowSubscription implements Subscription { int recurseLevel = 0;
+     * @Override public void request(long n) { boolean goodToGo = recurseLevel++
+     * == 0;
+     *
+     * while (goodToGo && buffers.size() > 0 && n > 0) { ByteBuffer buf =
+     * buffers.get(0); subscriber.onNext(buf); n--; } buffersWindow += n;
+     * flowController.accept(n * bufferSize); recurseLevel--; }
+     *
+     * @Override public void cancel() { // ?? set flag and throw exception on
+     * next receipt of buffer } }
+     *
+     * @Override public U onResponseBodyStart(long contentLength, HttpHeaders
+     * responseHeaders, LongConsumer flowController) throws IOException {
+     * this.subscriber = subscriber; this.flowController = flowController;
+     * this.subscription = new FlowSubscription(); this.bufferSize = bufferSize;
+     * subscriber.onSubscribe(subscription); return null; }
+     *
+     * @Override public void onResponseError(Throwable t) {
+     * subscriber.onError(t); }
+     *
+     * @Override public void onResponseBodyChunk(ByteBuffer b) throws
+     * IOException { if (buffersWindow > 0) { buffersWindow --;
+     * subscriber.onNext(b); } else { buffers.add(b); // or could combine
+     * buffers? } }
+     *
+     * @Override public U onResponseComplete() throws IOException {
+     * subscriber.onComplete(); return bodySupplier.get(); } }; }
+     */
+    private static final ByteBuffer EOF = ByteBuffer.allocate(0);
+    private static final ByteBuffer CLOSED = ByteBuffer.allocate(0);
+
+    // prototype using ByteBuffer based flow control. InputStream feeds off a
+    // BlockingQueue. Size of Q is determined from the the bufsize (bytes) and
+    // the default ByteBuffer size. bufsize should be a reasonable multiple of
+    // ByteBuffer size to prevent underflow/starvation. The InputStream updates
+    // the flowControl window by one as each ByteBuffer is fully consumed.
+    // Special sentinels are used to indicate stream closed and EOF.
+    /**
+     * Returns a response body processor which provides an InputStream to read
+     * the body.
+     *
+     * @implNote This mechanism is provided primarily for backwards
+     * compatibility for code that expects InputStream. It is recommended for
+     * better performance to use one of the other response processor
+     * implementations.
+     *
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<InputStream> asInputStream() {
+        return new BodyProcessor<InputStream>() {
+            int queueSize = 2;
+            private volatile Throwable throwable;
+
+            BlockingQueue<ByteBuffer> queue  = new LinkedBlockingQueue<>();
+
+            private void closeImpl() {
+                try {
+                    queue.put(CLOSED);
+                } catch (InterruptedException e) { }
+            }
+
+            @Override
+            public InputStream onResponseBodyStart(long contentLength,
+                                                   HttpHeaders responseHeaders,
+                                                   LongConsumer flowController)
+                throws IOException
+            {
+                flowController.accept(queueSize);
+
+                return new InputStream() {
+                    ByteBuffer buffer;
+
+                    @Override
+                    public int read() throws IOException {
+                        byte[] bb = new byte[1];
+                        int n = read(bb, 0, 1);
+                        if (n == -1) {
+                            return -1;
+                        } else {
+                            return bb[0];
+                        }
+                    }
+
+                    @Override
+                    public int read(byte[] bb) throws IOException {
+                        return read(bb, 0, bb.length);
+                    }
+
+                    @Override
+                    public int read(byte[] bb, int offset, int length)
+                        throws IOException
+                    {
+                        int n;
+                        if (getBuffer()) {
+                            return -1; // EOF
+                        } else {
+                            int remaining = buffer.remaining();
+                            if (length >= remaining) {
+                                buffer.get(bb, offset, remaining);
+                                return remaining;
+                            } else {
+                                buffer.get(bb, offset, length);
+                                return length;
+                            }
+                        }
+                    }
+
+                    @Override
+                    public void close() {
+                        closeImpl();
+                    }
+
+                    private boolean getBuffer() throws IOException {
+                        while (buffer == null || (buffer != EOF &&
+                                buffer != CLOSED && !buffer.hasRemaining())) {
+                            try {
+                                buffer = queue.take();
+                                flowController.accept(1);
+                            } catch (InterruptedException e) {
+                                throw new IOException(e);
+                            }
+                        }
+                        if (buffer == CLOSED) {
+                            if (throwable != null) {
+                                if (throwable instanceof IOException) {
+                                    throw (IOException) throwable;
+                                } else {
+                                    throw new IOException(throwable);
+                                }
+                            }
+                            throw new IOException("Closed");
+                        }
+
+                        if (buffer == EOF) {
+                            return true; // EOF
+                        }
+                        return false; // not EOF
+                    }
+
+                };
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                throwable = t;
+                closeImpl();
+            }
+
+            @Override
+            public void onResponseBodyChunk(ByteBuffer b) throws IOException {
+                try {
+                    queue.put(Utils.copy(b));
+                } catch (InterruptedException e) {
+                    // shouldn't happen as queue should never block
+                    throw new IOException(e);
+                }
+            }
+
+            @Override
+            public InputStream onResponseComplete() throws IOException {
+                try {
+                    queue.put(EOF);
+                } catch (InterruptedException e) {
+                    throw new IOException(e); // can't happen
+                }
+                return null;
+            }
+
+        };
+    }
+
+    /**
+     * Common super class that takes care of flow control
+     *
+     * @param <T>
+     */
+    private static abstract class AbstractResponseProcessor<T>
+        implements BodyProcessor<T>
+    {
+        LongConsumer flowController;
+
+        @Override
+        public final T onResponseBodyStart(long contentLength,
+                                           HttpHeaders responseHeaders,
+                                           LongConsumer flowController)
+            throws IOException
+        {
+            this.flowController = flowController;
+            flowController.accept(1);
+            return onResponseBodyStartImpl(contentLength, responseHeaders);
+        }
+
+        public abstract T onResponseBodyStartImpl(long contentLength,
+                                                  HttpHeaders responseHeaders)
+            throws IOException;
+
+        public abstract void onResponseBodyChunkImpl(ByteBuffer b)
+            throws IOException;
+
+        @Override
+        public final void onResponseBodyChunk(ByteBuffer b) throws IOException {
+            onResponseBodyChunkImpl(b);
+            flowController.accept(1);
+        }
+    }
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;byte[]&gt; which returns the response
+     * body as a {@code byte array}.
+     *
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<byte[]> asByteArray() {
+        ByteArrayResponseProcessor brp = new ByteArrayResponseProcessor();
+
+        return new AbstractResponseProcessor<byte[]>() {
+
+            @Override
+            public byte[] onResponseBodyStartImpl(long contentLength,
+                                                  HttpHeaders h)
+                throws IOException
+            {
+                brp.onStart(contentLength);
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b)
+                throws IOException
+            {
+                brp.onBodyContent(b);
+            }
+
+            @Override
+            public byte[] onResponseComplete() throws IOException {
+                return brp.onComplete();
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                brp.onError(t);
+            }
+        };
+    }
+
+    /**
+     * Returns a response processor which decodes the body using the character
+     * set specified in the {@code Content-encoding} response header. If there
+     * is no such header, or the character set is not supported, then
+     * {@link java.nio.charset.StandardCharsets#ISO_8859_1 ISO_8859_1} is used.
+     *
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<String> asString() {
+        return asString(null);
+    }
+
+    /**
+     * Returns a MultiProcessor that handles multiple responses, writes the
+     * response bodies to files and which returns an aggregate response object
+     * that is a {@code Map<URI,Path>}. The keyset of the Map represents the
+     * URIs of the original request and any additional requests generated by the
+     * server. The values are the paths of the destination files. Each path uses
+     * the URI path of the request offset from the destination parent directory
+     * provided.
+     *
+     * <p> All incoming additional requests (push promises) are accepted by this
+     * multi response processor. Errors are effectively ignored and any failed
+     * responses are simply omitted from the result Map. Other implementations
+     * of MultiProcessor can handle these situations
+     *
+     * <p><b>Example usage</b>
+     * <pre>
+     * {@code
+     *    CompletableFuture<Map<URI,Path>> cf =
+     *    HttpRequest.create(new URI("https://www.foo.com/"))
+     *               .version(Version.HTTP2)
+     *               .GET()
+     *               .sendAsyncMulti(HttpResponse.multiFile("/usr/destination"));
+     *
+     *    Map<URI,Path> results = cf.join();
+     * }
+     * </pre>
+     *
+     * @param destination the destination parent directory of all response
+     * bodies
+     * @return a MultiProcessor
+     */
+    public static MultiProcessor<Map<URI, Path>> multiFile(Path destination) {
+
+        return new MultiProcessor<Map<URI, Path>>() {
+            Map<URI, CompletableFuture<Path>> bodyCFs = new HashMap<>();
+
+            Map<URI, Path> results = new HashMap<>();
+
+            @Override
+            public BiFunction<HttpRequest, CompletableFuture<HttpResponse>, Boolean>
+            onStart(HttpRequest mainRequest,
+                    CompletableFuture<HttpResponse> response) {
+                bodyCFs.put(mainRequest.uri(), getBody(mainRequest, response));
+                return (HttpRequest additional, CompletableFuture<HttpResponse> cf) -> {
+                    CompletableFuture<Path> bcf = getBody(additional, cf);
+                    bodyCFs.put(additional.uri(), bcf);
+                    // we accept all comers
+                    return true;
+                };
+            }
+
+            private CompletableFuture<Path> getBody(HttpRequest req,
+                                                    CompletableFuture<HttpResponse> cf) {
+                URI u = req.uri();
+                String path = u.getPath();
+                return cf.thenCompose((HttpResponse resp) -> {
+                    return resp.bodyAsync(HttpResponse.asFile(destination.resolve(path)));
+                });
+            }
+
+            @Override
+            public Map<URI, Path> onComplete() {
+                // all CFs have completed normally or in error.
+                Set<Map.Entry<URI, CompletableFuture<Path>>> entries = bodyCFs.entrySet();
+                for (Map.Entry<URI, CompletableFuture<Path>> entry : entries) {
+                    CompletableFuture<Path> v = entry.getValue();
+                    URI uri = entry.getKey();
+                    if (v.isDone() && !v.isCompletedExceptionally()) {
+                        results.put(uri, v.join());
+                    }
+                }
+                return results;
+            }
+        };
+    }
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;{@link String}&gt;.
+     *
+     * @param charset the name of the charset to interpret the body as. If
+     * {@code null} then the processor tries to determine the character set from
+     * the {@code Content-encoding} header. If that charset is not supported
+     * then {@link java.nio.charset.StandardCharsets#ISO_8859_1 ISO_8859_1} is
+     * used.
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<String> asString(Charset charset) {
+
+        ByteArrayResponseProcessor brp = new ByteArrayResponseProcessor();
+
+        return new AbstractResponseProcessor<String>() {
+            Charset cs = charset;
+            HttpHeaders headers;
+
+            @Override
+            public String onResponseBodyStartImpl(long contentLength,
+                                                  HttpHeaders h)
+                throws IOException
+            {
+                headers = h;
+                brp.onStart(contentLength);
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b) throws IOException {
+                brp.onBodyContent(b);
+            }
+
+            @Override
+            public String onResponseComplete() throws IOException {
+                byte[] buf = brp.onComplete();
+                if (cs == null) {
+                    cs = headers.firstValue("Content-encoding")
+                                .map((String s) -> Charset.forName(s))
+                                .orElse(StandardCharsets.ISO_8859_1);
+                }
+                return new String(buf, cs);
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                brp.onError(t);
+            }
+
+        };
+    }
+
+    /**
+     * Returns a response processor which ignores the response body.
+     *
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Void> ignoreBody() {
+        return asByteArrayConsumer((byte[] buf) -> { /* ignore */ });
+    }
+
+    /**
+     * A processor for response bodies, which determines the type of the
+     * response body returned from {@link HttpResponse}. Response processors can
+     * either return an object that represents the body itself (after it has
+     * been read) or else an object that is used to read the body (such as an
+     * {@code InputStream}). The parameterized type {@code <T>} is the type of
+     * the returned body object from
+     * {@link HttpResponse#body(BodyProcessor) HttpResponse.body} and
+     * (indirectly) from {@link HttpResponse#bodyAsync(BodyProcessor)
+     * HttpResponse.bodyAsync}.
+     *
+     * <p> Implementations of this interface are provided in {@link HttpResponse}
+     * which write responses to {@code String, byte[], File, Consumer<byte[]>}.
+     * Custom implementations can also be used.
+     *
+     * <p> The methods of this interface may be called from multiple threads,
+     * but only one method is invoked at a time, and behaves as if called from
+     * one thread.
+     *
+     * @param <T> the type of the response body
+     *
+     * @since 9
+     */
+    public interface BodyProcessor<T> {
+
+        /**
+         * Called immediately before the response body is read. If {@code <T>}
+         * is an object used to read or accept the response body, such as a
+         * {@code Consumer} or {@code InputStream} then it should be returned
+         * from this method, and the body object will be returned before any
+         * data is read. If {@code <T>} represents the body itself after being
+         * read, then this method must return {@code null} and the body will be
+         * returned from {@link #onResponseComplete()}. In both cases, the
+         * actual body data is provided by the
+         * {@link #onResponseBodyChunk(ByteBuffer) onResponseBodyChunk} method
+         * in exactly the same way.
+         *
+         * <p> flowController is a consumer of long values and is used for
+         * updating a flow control window as follows. The window represents the
+         * number of times
+         * {@link #onResponseBodyChunk(java.nio.ByteBuffer) onResponseBodyChunk}
+         * may be called before receiving further updates to the window. Each
+         * time it is called, the window is reduced by {@code 1}. When the
+         * window reaches zero {@code onResponseBodyChunk()} will not be called
+         * again until the window has opened again with further calls to
+         * flowController.accept().
+         * {@link java.util.function.LongConsumer#accept(long) flowcontroller.accept()}
+         * must be called to open (increase) the window by the specified amount.
+         * The initial value is zero. This implies that if {@code
+         * onResponseBodyStart()} does not call {@code flowController.accept()}
+         * with a positive value no data will ever be delivered.
+         *
+         * @param contentLength {@code -1} signifies unknown content length.
+         *                      Otherwise, a positive integer, or zero.
+         * @param responseHeaders the response headers
+         * @param flowController a LongConsumer used to update the flow control
+         *                       window
+         * @return {@code null} or an object that can be used to read the
+         *         response body.
+         * @throws IOException if an exception occurs starting the response
+         *                     body receive
+         */
+        T onResponseBodyStart(long contentLength,
+                              HttpHeaders responseHeaders,
+                              LongConsumer flowController)
+            throws IOException;
+
+        /**
+         * Called if an error occurs while reading the response body. This
+         * terminates the operation and no further calls will occur after this.
+         *
+         * @param t the Throwable
+         */
+        void onResponseError(Throwable t);
+
+        /**
+         * Called for each buffer of data received for this response.
+         * ByteBuffers can be reused as soon as this method returns.
+         *
+         * @param b a ByteBuffer whose position is at the first byte that can be
+         *          read, and whose limit is after the last byte that can be read
+         * @throws IOException in case of I/O error
+         */
+        void onResponseBodyChunk(ByteBuffer b) throws IOException;
+
+        /**
+         * Called after the last time
+         * {@link #onResponseBodyChunk(java.nio.ByteBuffer)} has been called and
+         * returned indicating that the entire content has been read. This
+         * method must return an object that represents or contains the response
+         * body just received, but only if an object was not returned from
+         * {@link #onResponseBodyStart(long, HttpHeaders, LongConsumer)
+         * onResponseBodyStart}.
+         *
+         * @return a T, or {@code null} if an object was already returned
+         * @throws IOException in case of I/O error
+         */
+        T onResponseComplete() throws IOException;
+    }
+
+    /**
+     * A response processor for a HTTP/2 multi response. A multi response
+     * comprises a main response, and zero or more additional responses. Each
+     * additional response is sent by the server in response to requests that
+     * the server also generates. Additional responses are typically resources
+     * that the server guesses the client will need which are related to the
+     * initial request.
+     *
+     * <p>The server generated requests are also known as <i>push promises</i>.
+     * The server is permitted to send any number of these requests up to the
+     * point where the main response is fully received. Therefore, after
+     * completion of the main response body, the final number of additional
+     * responses is known. Additional responses may be cancelled, but given that
+     * the server does not wait for any acknowledgment before sending the
+     * response, this must be done quickly to avoid unnecessary data transmission.
+     *
+     * <p> {@code MultiProcessor}s are parameterised with a type {@code T} which
+     * represents some meaningful aggregate of the responses received. This
+     * would typically be a Collection of response or response body objects. One
+     * example implementation can be found at {@link
+     * HttpResponse#multiFile(java.nio.file.Path)}.
+     *
+     * @param <T> a type representing the aggregated results
+     *
+     * @since 9
+     */
+    public interface MultiProcessor<T> {
+
+        /**
+         * Called before or soon after a multi request is sent. The request that
+         * initiated the multi response is supplied, as well as a
+         * CompletableFuture for the main response. The implementation of this
+         * method must return a BiFunction which is called once for each push
+         * promise received.
+         *
+         * <p> The parameters to the {@code BiFunction} are the {@code HttpRequest}
+         * for the push promise and a {@code CompletableFuture} for its
+         * response. The function must return a Boolean indicating whether the
+         * push promise has been accepted (true) or should be canceled (false).
+         * The CompletableFutures for any canceled pushes are themselves
+         * completed exceptionally soon after the function returns.
+         *
+         * @param mainRequest the main request
+         * @param response a CompletableFuture for the main response
+         * @return a BiFunction that is called for each push promise
+         */
+        BiFunction<HttpRequest, CompletableFuture<HttpResponse>, Boolean>
+        onStart(HttpRequest mainRequest,
+                CompletableFuture<HttpResponse> response);
+
+        /**
+         * Called after all responses associated with the multi response have
+         * been fully processed, including response bodies.
+         *
+         * <p> Example types for {@code T} could be Collections of response body
+         * types or {@code Map}s from request {@code URI} to a response body
+         * type.
+         *
+         * @return the aggregate response object
+         */
+        T onComplete();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,157 @@
+/*
+ * 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.net.URI;
+import java.nio.ByteBuffer;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.LongConsumer;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * The implementation class for HttpResponse
+ */
+class HttpResponseImpl extends HttpResponse {
+
+    int responseCode;
+    Exchange exchange;
+    HttpRequestImpl request;
+    HttpHeaders1 headers;
+    HttpHeaders1 trailers;
+    SSLParameters sslParameters;
+    URI uri;
+    HttpClient.Version version;
+    AccessControlContext acc;
+    RawChannel rawchan;
+    HttpConnection connection;
+
+    public HttpResponseImpl(int responseCode, Exchange exch, HttpHeaders1 headers,
+            HttpHeaders1 trailers, SSLParameters sslParameters,
+            HttpClient.Version version, HttpConnection connection) {
+        this.responseCode = responseCode;
+        this.exchange = exch;
+        this.request = exchange.request();
+        this.headers = headers;
+        this.trailers = trailers;
+        this.sslParameters = sslParameters;
+        this.uri = request.uri();
+        this.version = version;
+        this.connection = connection;
+    }
+
+    @Override
+    public int statusCode() {
+        return responseCode;
+    }
+
+    @Override
+    public HttpRequestImpl request() {
+        return request;
+    }
+
+    @Override
+    public HttpHeaders headers() {
+        headers.makeUnmodifiable();
+        return headers;
+    }
+
+    @Override
+    public HttpHeaders trailers() {
+        trailers.makeUnmodifiable();
+        return trailers;
+    }
+
+
+    @Override
+    public <T> T body(java.net.http.HttpResponse.BodyProcessor<T> processor) {
+        return exchange.responseBody(processor);
+    }
+
+    @Override
+    public <T> CompletableFuture<T> bodyAsync(java.net.http.HttpResponse.BodyProcessor<T> processor) {
+        acc = AccessController.getContext();
+        return exchange.responseBodyAsync(processor);
+    }
+
+    @Override
+    public SSLParameters sslParameters() {
+        return sslParameters;
+    }
+
+    public AccessControlContext getAccessControlContext() {
+        return acc;
+    }
+
+    @Override
+    public URI uri() {
+        return uri;
+    }
+
+    @Override
+    public HttpClient.Version version() {
+        return version;
+    }
+    // keepalive flag determines whether connection is closed or kept alive
+    // by reading/skipping data
+
+    public static java.net.http.HttpResponse.BodyProcessor<Void> ignoreBody(boolean keepalive) {
+        return new java.net.http.HttpResponse.BodyProcessor<Void>() {
+
+            @Override
+            public Void onResponseBodyStart(long clen, HttpHeaders h,
+                    LongConsumer flowController) throws IOException {
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunk(ByteBuffer b) throws IOException {
+            }
+
+            @Override
+            public Void onResponseComplete() throws IOException {
+                return null;
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+            }
+        };
+    }
+
+    /**
+     *
+     * @return
+     */
+    RawChannel rawChannel() {
+        if (rawchan == null) {
+            rawchan = new RawChannel(request.client(), connection);
+        }
+        return rawchan;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpTimeoutException.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * Thrown when a response is not received within a specified time period.
+ */
+public class HttpTimeoutException extends IOException {
+
+    private static final long serialVersionUID = 981344271622632951L;
+
+    public HttpTimeoutException(String message) {
+        super(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,170 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.util.Locale;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * -Djava.net.HttpClient.log=errors,requests,headers,frames[:type:type2:..],content
+ *
+ * Any of errors, requests, headers or content are optional.
+ *
+ * Other handlers may be added. All logging is at level INFO
+ *
+ * Logger name is "java.net.http.HttpClient"
+ */
+class Log {
+
+    final static String logProp = "java.net.http.HttpClient.log";
+
+    public static final int OFF = 0;
+    public static final int ERRORS = 0x1;
+    public static final int REQUESTS = 0x2;
+    public static final int HEADERS = 0x4;
+    public static final int CONTENT = 0x8;
+    public static final int FRAMES = 0x10;
+    public static final int SSL = 0x20;
+    static int logging;
+
+    // Frame types: "control", "data", "window", "all"
+    public static final int CONTROL = 1; // all except DATA and WINDOW_UPDATES
+    public static final int DATA = 2;
+    public static final int WINDOW_UPDATES = 4;
+    public static final int ALL = CONTROL| DATA | WINDOW_UPDATES;
+    static int frametypes;
+
+    static sun.util.logging.PlatformLogger logger;
+
+    static {
+        String s = Utils.getNetProperty(logProp);
+        if (s == null) {
+            logging = OFF;
+        } else {
+            String[] vals = s.split(",");
+            for (String val : vals) {
+                switch (val.toLowerCase(Locale.US)) {
+                    case "errors":
+                        logging |= ERRORS;
+                        break;
+                    case "requests":
+                        logging |= REQUESTS;
+                        break;
+                    case "headers":
+                        logging |= HEADERS;
+                        break;
+                    case "content":
+                        logging |= CONTENT;
+                        break;
+                    case "ssl":
+                        logging |= SSL;
+                        break;
+                    case "all":
+                        logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS;
+                        break;
+                }
+                if (val.startsWith("frames")) {
+                    logging |= FRAMES;
+                    String[] types = val.split(":");
+                    if (types.length == 1) {
+                        frametypes = CONTROL | DATA | WINDOW_UPDATES;
+                    } else {
+                        for (String type : types) {
+                            switch (type.toLowerCase()) {
+                                case "control":
+                                    frametypes |= CONTROL;
+                                    break;
+                                case "data":
+                                    frametypes |= DATA;
+                                    break;
+                                case "window":
+                                    frametypes |= WINDOW_UPDATES;
+                                    break;
+                                case "all":
+                                    frametypes = ALL;
+                                    break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (logging != OFF) {
+            logger = PlatformLogger.getLogger("java.net.http.HttpClient");
+        }
+    }
+
+    static boolean errors() {
+        return (logging & ERRORS) != 0;
+    }
+
+    static boolean requests() {
+        return (logging & REQUESTS) != 0;
+    }
+
+    static boolean headers() {
+        return (logging & HEADERS) != 0;
+    }
+
+    static boolean ssl() {
+        return (logging & SSL) != 0;
+    }
+
+    static boolean frames() {
+        return (logging & FRAMES) != 0;
+    }
+
+    static void logError(String s) {
+        if (errors())
+            logger.info("ERROR: " + s);
+    }
+
+    static void logError(Throwable t) {
+        if (errors()) {
+            String s = Utils.stackTrace(t);
+            logger.info("ERROR: " + s);
+        }
+    }
+
+    static void logSSL(String s) {
+        if (ssl())
+            logger.info("SSL: " + s);
+    }
+
+    static void logRequest(String s) {
+        if (requests())
+            logger.info("REQUEST: " + s);
+    }
+
+    static void logResponse(String s) {
+        if (requests())
+            logger.info("RESPONSE: " + s);
+    }
+
+    static void logHeaders(String s) {
+        if (headers())
+            logger.info("HEADERS: " + s);
+    }
+// END HTTP2
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,275 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.function.BiFunction;
+
+import static java.net.http.Pair.pair;
+
+/**
+ * Encapsulates multiple Exchanges belonging to one HttpRequestImpl.
+ * - manages filters
+ * - retries due to filters.
+ * - I/O errors and most other exceptions get returned directly to user
+ *
+ * Creates a new Exchange for each request/response interaction
+ */
+class MultiExchange {
+
+    final HttpRequestImpl request; // the user request
+    final HttpClientImpl client;
+    HttpRequestImpl currentreq; // used for async only
+    Exchange exchange; // the current exchange
+    Exchange previous;
+    int attempts;
+    // Maximum number of times a request will be retried/redirected
+    // for any reason
+
+    final static int DEFAULT_MAX_ATTEMPTS = 5;
+    final static int max_attempts = Utils.getIntegerNetProperty(
+            "sun.net.httpclient.redirects.retrylimit", DEFAULT_MAX_ATTEMPTS
+    );
+
+    private final List<HeaderFilter> filters;
+    TimedEvent td;
+    boolean cancelled = false;
+
+    /**
+     * Filter fields. These are attached as required by filters
+     * and only used by the filter implementations. This could be
+     * generalised into Objects that are passed explicitly to the filters
+     * (one per MultiExchange object, and one per Exchange object possibly)
+     */
+    volatile AuthenticationFilter.AuthInfo serverauth, proxyauth;
+    // RedirectHandler
+    volatile int numberOfRedirects = 0;
+
+    /**
+     */
+    MultiExchange(HttpRequestImpl request) {
+        this.exchange = new Exchange(request);
+        this.previous = null;
+        this.request = request;
+        this.currentreq = request;
+        this.attempts = 0;
+        this.client = request.client();
+        this.filters = client.filterChain();
+    }
+
+    public HttpResponseImpl response() throws IOException, InterruptedException {
+        HttpRequestImpl r = request;
+        if (r.timeval() != 0) {
+            // set timer
+            td = new TimedEvent(r.timeval());
+            client.registerTimer(td);
+        }
+        while (attempts < max_attempts) {
+            try {
+                attempts++;
+                Exchange currExchange = getExchange();
+                requestFilters(r);
+                HttpResponseImpl response = currExchange.response();
+                Pair<HttpResponse, HttpRequestImpl> filterResult = responseFilters(response);
+                HttpRequestImpl newreq = filterResult.second;
+                if (newreq == null) {
+                    if (attempts > 1) {
+                        Log.logError("Succeeded on attempt: " + attempts);
+                    }
+                    cancelTimer();
+                    return response;
+                }
+                response.body(HttpResponse.ignoreBody());
+                setExchange(new Exchange(newreq, currExchange.getAccessControlContext() ));
+                r = newreq;
+            } catch (IOException e) {
+                if (cancelled) {
+                    throw new HttpTimeoutException("Request timed out");
+                }
+                throw e;
+            }
+        }
+        cancelTimer();
+        throw new IOException("Retry limit exceeded");
+    }
+
+    private synchronized Exchange getExchange() {
+        return exchange;
+    }
+
+    private synchronized void setExchange(Exchange exchange) {
+        this.exchange = exchange;
+    }
+
+    private void cancelTimer() {
+        if (td != null) {
+            client.cancelTimer(td);
+        }
+    }
+
+    private void requestFilters(HttpRequestImpl r) throws IOException {
+        for (HeaderFilter filter : filters) {
+            filter.request(r);
+        }
+    }
+
+    // Filters are assumed to be non-blocking so the async
+    // versions of these methods just call the blocking ones
+
+    private CompletableFuture<Void> requestFiltersAsync(HttpRequestImpl r) {
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        try {
+            requestFilters(r);
+            cf.complete(null);
+        } catch(Throwable e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+
+
+    private Pair<HttpResponse,HttpRequestImpl>
+    responseFilters(HttpResponse response) throws IOException
+    {
+        for (HeaderFilter filter : filters) {
+            HttpRequestImpl newreq = filter.response((HttpResponseImpl)response);
+            if (newreq != null) {
+                return pair(null, newreq);
+            }
+        }
+        return pair(response, null);
+    }
+
+    private CompletableFuture<Pair<HttpResponse,HttpRequestImpl>>
+    responseFiltersAsync(HttpResponse response)
+    {
+        CompletableFuture<Pair<HttpResponse,HttpRequestImpl>> cf = new CompletableFuture<>();
+        try {
+            Pair<HttpResponse,HttpRequestImpl> n = responseFilters(response); // assumed to be fast
+            cf.complete(n);
+        } catch (Throwable e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+
+    public void cancel() {
+        cancelled = true;
+        getExchange().cancel();
+    }
+
+    public CompletableFuture<HttpResponseImpl> responseAsync(Void v) {
+        CompletableFuture<HttpResponseImpl> cf;
+        if (++attempts > max_attempts) {
+            cf = new CompletableFuture<>();
+            cf.completeExceptionally(new IOException("Too many retries"));
+        } else {
+            if (currentreq.timeval() != 0) {
+                // set timer
+                td = new TimedEvent(currentreq.timeval());
+                client.registerTimer(td);
+            }
+            Exchange exch = getExchange();
+            cf = requestFiltersAsync(currentreq)
+                .thenCompose(exch::responseAsync)
+                .thenCompose(this::responseFiltersAsync)
+                .thenCompose((Pair<HttpResponse,HttpRequestImpl> pair) -> {
+                    HttpResponseImpl resp = (HttpResponseImpl)pair.first;
+                    if (resp != null) {
+                        if (attempts > 1) {
+                            Log.logError("Succeeded on attempt: " + attempts);
+                        }
+                        return CompletableFuture.completedFuture(resp);
+                    } else {
+                        currentreq = pair.second;
+                        Exchange previous = exch;
+                        setExchange(new Exchange(currentreq,
+                                                 currentreq.getAccessControlContext()));
+                        //reads body off previous, and then waits for next response
+                        return previous
+                                .responseBodyAsync(HttpResponse.ignoreBody())
+                                .thenCompose(this::responseAsync);
+                    }
+                })
+            .handle((BiFunction<HttpResponse, Throwable, Pair<HttpResponse, Throwable>>) Pair::new)
+            .thenCompose((Pair<HttpResponse,Throwable> obj) -> {
+                HttpResponseImpl response = (HttpResponseImpl)obj.first;
+                if (response != null) {
+                    return CompletableFuture.completedFuture(response);
+                }
+                // all exceptions thrown are handled here
+                CompletableFuture<HttpResponseImpl> error = getExceptionalCF(obj.second);
+                if (error == null) {
+                    cancelTimer();
+                    return responseAsync(null);
+                } else {
+                    return error;
+                }
+            });
+        }
+        return cf;
+    }
+
+    /**
+     * Take a Throwable and return a suitable CompletableFuture that is
+     * completed exceptionally.
+     */
+    private CompletableFuture<HttpResponseImpl> getExceptionalCF(Throwable t) {
+        CompletableFuture<HttpResponseImpl> error = new CompletableFuture<>();
+        if ((t instanceof CompletionException) || (t instanceof ExecutionException)) {
+            if (t.getCause() != null) {
+                t = t.getCause();
+            }
+        }
+        if (cancelled && t instanceof IOException) {
+            t = new HttpTimeoutException("request timed out");
+        }
+        error.completeExceptionally(t);
+        return error;
+    }
+
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor) {
+        return getExchange().responseBody(processor);
+    }
+
+    <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+        return getExchange().responseBodyAsync(processor);
+    }
+
+    class TimedEvent extends TimeoutEvent {
+        TimedEvent(long timeval) {
+            super(timeval);
+        }
+        @Override
+        public void handle() {
+            cancel();
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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  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
+ * 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
+ * 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;
+
+/**
+ * A simple paired value class
+ */
+final class Pair<T, U> {
+
+    Pair(T first, U second) {
+        this.second = second;
+        this.first = first;
+    }
+
+    final T first;
+    final U second;
+
+    // Because 'pair()' is shorter than 'new Pair<>()'.
+    // Sometimes this difference might be very significant (especially in a
+    // 80-ish characters boundary). Sorry diamond operator.
+    static <T, U> Pair<T, U> pair(T first, U second) {
+        return new Pair<>(first, second);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,228 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.StandardSocketOptions;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Plain raw TCP connection direct to destination
+ */
+class PlainHttpConnection extends HttpConnection {
+
+    protected SocketChannel chan;
+    private volatile boolean connected;
+    private boolean closed;
+
+    class ConnectEvent extends AsyncEvent implements AsyncEvent.Blocking {
+        CompletableFuture<Void> cf;
+
+        ConnectEvent(CompletableFuture<Void> cf) {
+            this.cf = cf;
+        }
+
+        @Override
+        public SelectableChannel channel() {
+            return chan;
+        }
+
+        @Override
+        public int interestOps() {
+            return SelectionKey.OP_CONNECT;
+        }
+
+        @Override
+        public void handle() {
+            try {
+                chan.finishConnect();
+            } catch (IOException e) {
+                cf.completeExceptionally(e);
+            }
+            connected = true;
+            cf.complete(null);
+        }
+
+        @Override
+        public void abort() {
+            close();
+        }
+    }
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        CompletableFuture<Void> plainFuture = new CompletableFuture<>();
+        try {
+            chan.configureBlocking(false);
+            chan.connect(address);
+            client.registerEvent(new ConnectEvent(plainFuture));
+        } catch (IOException e) {
+            plainFuture.completeExceptionally(e);
+        }
+        return plainFuture;
+    }
+
+    @Override
+    public void connect() throws IOException {
+        chan.connect(address);
+        connected = true;
+    }
+
+    @Override
+    SocketChannel channel() {
+        return chan;
+    }
+
+    PlainHttpConnection(InetSocketAddress addr, HttpClientImpl client) {
+        super(addr, client);
+        try {
+            this.chan = SocketChannel.open();
+            int bufsize = client.getReceiveBufferSize();
+            chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    @Override
+    long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        //debugPrint("Send", buffers, start, number);
+        return chan.write(buffers, start, number);
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        //debugPrint("Send", buffer);
+        return chan.write(buffer);
+    }
+
+    @Override
+    public String toString() {
+        return "PlainHttpConnection: " + super.toString();
+    }
+
+    /**
+     * Close this connection
+     */
+    @Override
+    synchronized void close() {
+        if (closed)
+            return;
+        closed = true;
+        try {
+            Log.logError("Closing: " + toString());
+            //System.out.println("Closing: " + this);
+            chan.close();
+        } catch (IOException e) {}
+    }
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        ByteBuffer buf = getBuffer(); // TODO not using length
+        int n = chan.read(buf);
+        if (n == -1) {
+            return null;
+        }
+        buf.flip();
+        String s = "Receive (" + n + " bytes) ";
+        //debugPrint(s, buf);
+        return buf;
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buf) throws IOException {
+        int mark = buf.position();
+        int n = chan.read(buf);
+        if (n == -1) {
+            return -1;
+        }
+        Utils.flipToMark(buffer, mark);
+        String s = "Receive (" + n + " bytes) ";
+        //debugPrint(s, buf);
+        return n;
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return new ConnectionPool.CacheKey(address, null);
+    }
+
+    @Override
+    synchronized boolean connected() {
+        return connected;
+    }
+
+    class ReceiveResponseEvent extends AsyncEvent implements AsyncEvent.Blocking {
+        CompletableFuture<Void> cf;
+
+        ReceiveResponseEvent(CompletableFuture<Void> cf) {
+            this.cf = cf;
+        }
+        @Override
+        public SelectableChannel channel() {
+            return chan;
+        }
+
+        @Override
+        public void handle() {
+            cf.complete(null);
+        }
+
+        @Override
+        public int interestOps() {
+            return SelectionKey.OP_READ;
+        }
+
+        @Override
+        public void abort() {
+            close();
+        }
+    }
+
+    @Override
+    boolean isSecure() {
+        return false;
+    }
+
+    @Override
+    boolean isProxied() {
+        return false;
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        try {
+            client.registerEvent(new ReceiveResponseEvent(cf));
+        } catch (IOException e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainProxyConnection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,39 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.net.InetSocketAddress;
+
+class PlainProxyConnection extends PlainHttpConnection {
+
+    PlainProxyConnection(InetSocketAddress proxy, HttpClientImpl client) {
+        super(proxy, client);
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return new ConnectionPool.CacheKey(null, address);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,143 @@
+/*
+ * 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.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.security.AccessControlContext;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * A plain text socket tunnel through a proxy. Uses "CONNECT" but does not
+ * encrypt. Used by WebSockets. Subclassed in SSLTunnelConnection for encryption.
+ */
+class PlainTunnelingConnection extends HttpConnection {
+
+    final PlainHttpConnection delegate;
+    protected final InetSocketAddress proxyAddr;
+    private volatile boolean connected;
+    private final AccessControlContext acc;
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        return delegate.connectAsync()
+            .thenCompose((Void v) -> {
+                HttpRequestImpl req = new HttpRequestImpl(client, "CONNECT", address);
+                Exchange connectExchange = new Exchange(req, acc);
+                return connectExchange
+                    .responseAsyncImpl(delegate)
+                    .thenCompose((HttpResponse r) -> {
+                        CompletableFuture<Void> cf = new CompletableFuture<>();
+                        if (r.statusCode() != 200) {
+                            cf.completeExceptionally(new IOException("Tunnel failed"));
+                        } else {
+                            connected = true;
+                            cf.complete(null);
+                        }
+                        return cf;
+                    });
+            });
+    }
+
+    @Override
+    public void connect() throws IOException, InterruptedException {
+        delegate.connect();
+        HttpRequestImpl req = new HttpRequestImpl(client, "CONNECT", address);
+        Exchange connectExchange = new Exchange(req, acc);
+        HttpResponse r = connectExchange.responseImpl(delegate);
+        if (r.statusCode() != 200) {
+            throw new IOException("Tunnel failed");
+        }
+        connected = true;
+    }
+
+    @Override
+    boolean connected() {
+        return connected;
+    }
+
+    protected PlainTunnelingConnection(InetSocketAddress addr,
+                                       InetSocketAddress proxy,
+                                       HttpClientImpl client,
+                                       AccessControlContext acc) {
+        super(addr, client);
+        this.proxyAddr = proxy;
+        this.acc = acc;
+        delegate = new PlainHttpConnection(proxy, client);
+    }
+
+    @Override
+    SocketChannel channel() {
+        return delegate.channel();
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return new ConnectionPool.CacheKey(null, proxyAddr);
+    }
+
+    @Override
+    long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        return delegate.write(buffers, start, number);
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        return delegate.write(buffer);
+    }
+
+    @Override
+    void close() {
+        delegate.close();
+        connected = false;
+    }
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        return delegate.readImpl(length);
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        return delegate.whenReceivingResponse();
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buffer) throws IOException {
+        return delegate.readImpl(buffer);
+    }
+
+    @Override
+    boolean isSecure() {
+        return false;
+    }
+
+    @Override
+    boolean isProxied() {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,148 @@
+/*
+ * 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
+ */
+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;
+
+/**
+ * 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.
+ */
+class RawChannel implements ByteChannel, GatheringByteChannel {
+
+    private final HttpClientImpl client;
+    private final HttpConnection connection;
+    private boolean closed;
+
+    private interface RawEvent {
+
+        /** must return the selector interest op flags OR'd. */
+        int interestOps();
+
+        /** called when event occurs. */
+        void handle();
+    }
+
+    interface BlockingEvent extends RawEvent { }
+
+    interface NonBlockingEvent extends RawEvent { }
+
+    RawChannel(HttpClientImpl client, HttpConnection connection) {
+        this.client = client;
+        this.connection = connection;
+    }
+
+    private class RawAsyncEvent extends AsyncEvent {
+
+        private final RawEvent re;
+
+        RawAsyncEvent(RawEvent re) {
+            this.re = re;
+        }
+
+        public SelectableChannel channel() {
+            return connection.channel();
+        }
+
+        // must return the selector interest op flags OR'd
+        public int interestOps() {
+            return re.interestOps();
+        }
+
+        // called when event occurs
+        public void handle() {
+            re.handle();
+        }
+
+        public void abort() {}
+    }
+
+    private class BlockingRawAsyncEvent extends RawAsyncEvent
+            implements AsyncEvent.Blocking {
+
+        BlockingRawAsyncEvent(RawEvent re) {
+            super(re);
+        }
+    }
+
+    private class NonBlockingRawAsyncEvent extends RawAsyncEvent
+            implements AsyncEvent.NonBlocking {
+
+        NonBlockingRawAsyncEvent(RawEvent re) {
+            super(re);
+        }
+    }
+
+    /*
+     * 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 BlockingEvent) {
+            client.registerEvent(new BlockingRawAsyncEvent(event));
+        } else if (event instanceof NonBlockingEvent) {
+            client.registerEvent(new NonBlockingRawAsyncEvent(event));
+        } else {
+            throw new InternalError();
+        }
+    }
+
+    @Override
+    public int read(ByteBuffer dst) throws IOException {
+        return connection.read(dst);
+    }
+
+    @Override
+    public boolean isOpen() {
+        return !closed;
+    }
+
+    @Override
+    public void close() throws IOException {
+        closed = true;
+        connection.close();
+    }
+
+    @Override
+    public long write(ByteBuffer[] src) throws IOException {
+        return connection.write(src, 0, src.length);
+    }
+
+    @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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,96 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+
+class RedirectFilter implements HeaderFilter {
+
+    HttpRequestImpl requestImpl;
+    HttpRequest request;
+    HttpClientImpl client;
+    String method;
+    final static int DEFAULT_MAX_REDIRECTS = 5;
+    URI uri;
+
+    final static int max_redirects = Utils.getIntegerNetProperty(
+            "sun.net.httpclient.redirects.retrylimit", DEFAULT_MAX_REDIRECTS
+    );
+
+    @Override
+    public void request(HttpRequestImpl r) throws IOException {
+        this.request = r;
+        this.client = r.getClient();
+        this.method = r.method();
+        this.requestImpl = r;
+        this.uri = r.uri();
+    }
+
+    @Override
+    public HttpRequestImpl response(HttpResponseImpl r) throws IOException {
+        return handleResponse(r);
+    }
+
+    /**
+     * checks to see if new request needed and returns it.
+     * Null means response is ok to return to user.
+     */
+    private HttpRequestImpl handleResponse(HttpResponseImpl r) {
+        int rcode = r.statusCode();
+        if (rcode == 200) {
+            return null;
+        }
+        if (rcode >= 300 && rcode <= 399) {
+            URI redir = getRedirectedURI(r.headers());
+            if (canRedirect(r) && ++r.request.exchange.numberOfRedirects < max_redirects) {
+                //System.out.println("Redirecting to: " + redir);
+                return new HttpRequestImpl(redir, request, client, method, requestImpl);
+            } else {
+                //System.out.println("Redirect: giving up");
+                return null;
+            }
+        }
+        return null;
+    }
+
+    private URI getRedirectedURI(HttpHeaders headers) {
+        URI redirectedURI;
+        redirectedURI = headers.firstValue("Location")
+                .map((s) -> URI.create(s))
+                .orElseThrow(() -> new UncheckedIOException(
+                        new IOException("Invalid redirection")));
+
+        // redirect could be relative to original URL, but if not
+        // then redirect is used.
+        redirectedURI = uri.resolve(redirectedURI);
+        return redirectedURI;
+    }
+
+    private boolean canRedirect(HttpResponse r) {
+        return requestImpl.followRedirectsImpl().redirect(r);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseContent.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,323 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Implements chunked/fixed transfer encodings of HTTP/1.1 responses.
+ */
+class ResponseContent {
+
+    final HttpResponse.BodyProcessor<?> userProcessor;
+    final HttpResponse.BodyProcessor<?> pusher;
+    final HttpConnection connection;
+    final int contentLength;
+    ByteBuffer buffer;
+    ByteBuffer lastBufferUsed;
+    final ResponseHeaders headers;
+    final Http1Response.FlowController flowController;
+
+    ResponseContent(HttpConnection connection,
+                    int contentLength,
+                    ResponseHeaders h,
+                    HttpResponse.BodyProcessor<?> userProcessor,
+                    Http1Response.FlowController flowController) {
+        this.userProcessor = userProcessor;
+        this.pusher = (HttpResponse.BodyProcessor)userProcessor;
+        this.connection = connection;
+        this.contentLength = contentLength;
+        this.headers = h;
+        this.flowController = flowController;
+    }
+
+    static final int LF = 10;
+    static final int CR = 13;
+    static final int SP = 0x20;
+    static final int BUF_SIZE = 1024;
+
+    boolean chunkedContent, chunkedContentInitialized;
+
+    private boolean contentChunked() throws IOException {
+        if (chunkedContentInitialized) {
+            return chunkedContent;
+        }
+        if (contentLength == -1) {
+            String tc = headers.firstValue("Transfer-Encoding")
+                               .orElse("");
+            if (!tc.equals("")) {
+                if (tc.equalsIgnoreCase("chunked")) {
+                    chunkedContent = true;
+                } else {
+                    throw new IOException("invalid content");
+                }
+            } else {
+                chunkedContent = false;
+            }
+        }
+        chunkedContentInitialized = true;
+        return chunkedContent;
+    }
+
+    /**
+     * Entry point for pusher. b is an initial ByteBuffer that may
+     * have some data in it. When this method returns, the body
+     * has been fully processed.
+     */
+    void pushBody(ByteBuffer b) throws IOException {
+        // TODO: check status
+        if (contentChunked()) {
+            pushBodyChunked(b);
+        } else {
+            pushBodyFixed(b);
+        }
+    }
+
+    // reads and returns chunklen. Position of chunkbuf is first byte
+    // of chunk on return. chunklen includes the CR LF at end of chunk
+    int readChunkLen() throws IOException {
+        chunklen = 0;
+        boolean cr = false;
+        while (true) {
+            getHunk();
+            int c = chunkbuf.get();
+            if (cr) {
+                if (c == LF) {
+                    return chunklen + 2;
+                } else {
+                    throw new IOException("invalid chunk header");
+                }
+            }
+            if (c == CR) {
+                cr = true;
+            } else {
+                int digit = toDigit(c);
+                chunklen = chunklen * 16 + digit;
+            }
+        }
+    }
+
+    int chunklen = -1;      // number of bytes in chunk (fixed)
+    int bytesremaining;     // number of bytes in chunk left to be read incl CRLF
+    int bytesread;
+    ByteBuffer chunkbuf;    // initialise
+
+    // make sure we have at least 1 byte to look at
+    private void getHunk() throws IOException {
+        while (chunkbuf == null || !chunkbuf.hasRemaining()) {
+
+            if (chunkbuf != null) {
+                connection.returnBuffer(chunkbuf);
+            }
+            chunkbuf = connection.read();
+        }
+    }
+
+    private void consumeBytes(int n) throws IOException {
+        getHunk();
+        while (n > 0) {
+            int e = Math.min(chunkbuf.remaining(), n);
+            chunkbuf.position(chunkbuf.position() + e);
+            n -= e;
+            if (n > 0)
+                getHunk();
+        }
+    }
+
+    /**
+     * Returns a ByteBuffer containing a chunk of data or a "hunk" of data
+     * (a chunk of a chunk if the chunk size is larger than our ByteBuffers).
+     */
+    ByteBuffer readChunkedBuffer() throws IOException {
+        if (chunklen == -1) {
+            // new chunk
+            bytesremaining = readChunkLen();
+            chunklen = bytesremaining - 2;
+            if (chunklen == 0) {
+                consumeBytes(2);
+                return null;
+            }
+        }
+
+        getHunk();
+        bytesread = chunkbuf.remaining();
+        ByteBuffer returnBuffer;
+
+        /**
+         * Cases. Always at least one byte is read by getHunk()
+         *
+         * 1) one read contains exactly 1 chunk. Strip off CRLF and pass buffer on
+         * 2) one read contains a hunk. If at end of chunk, consume CRLF.Pass buffer up.
+         * 3) read contains rest of chunk and more data. Copy buffer.
+         */
+        if (bytesread == bytesremaining) {
+            // common case: 1 read = 1 chunk (or final hunk of chunk)
+            chunkbuf.limit(chunkbuf.limit() - 2); // remove trailing CRLF
+            bytesremaining = 0;
+            returnBuffer = chunkbuf;
+            chunkbuf = null;
+            chunklen = -1;
+        } else if (bytesread < bytesremaining) {
+            // read a hunk, maybe including CR or LF or both
+            bytesremaining -= bytesread;
+            if (bytesremaining <= 2) {
+                // remove any trailing CR LF already read, and then read the rest
+                chunkbuf.limit(chunkbuf.limit() - (2 - bytesremaining));
+                consumeBytes(bytesremaining);
+                chunklen = -1;
+            }
+            returnBuffer = chunkbuf;
+            chunkbuf = null;
+        } else {
+            // bytesread > bytesremaining
+            returnBuffer = splitChunkedBuffer(bytesremaining-2);
+            bytesremaining = 0;
+            chunklen = -1;
+            consumeBytes(2);
+        }
+        return returnBuffer;
+    }
+
+    ByteBuffer initialBuffer;
+    int fixedBytesReturned;
+
+    ByteBuffer getResidue() {
+        return lastBufferUsed;
+    }
+
+    private void compactBuffer(ByteBuffer buf) {
+        buf.compact()
+           .flip();
+    }
+
+    /**
+     * Copies inbuf (numBytes from its position) to new buffer. The returned
+     * buffer's position is zero and limit is at end (numBytes)
+     */
+    private ByteBuffer copyBuffer(ByteBuffer inbuf, int numBytes) {
+        ByteBuffer b1 = connection.getBuffer();
+        assert b1.remaining() >= numBytes;
+        byte[] b = b1.array();
+        inbuf.get(b, 0, numBytes);
+        b1.limit(numBytes);
+        return b1;
+    }
+
+    /**
+     * Split numBytes of data out of chunkbuf from the remainder,
+     * copying whichever part is smaller. chunkbuf points to second part
+     * of buffer on return. The returned buffer is the data from position
+     * to position + numBytes. Both buffers positions are reset so same
+     * data can be re-read.
+     */
+    private ByteBuffer splitChunkedBuffer(int numBytes) {
+        ByteBuffer newbuf = connection.getBuffer();
+        byte[] b = newbuf.array();
+        int midpoint = chunkbuf.position() + numBytes;
+        int remainder = chunkbuf.limit() - midpoint;
+
+        if (numBytes < remainder) {
+            // copy first part of chunkbuf to new buf
+            chunkbuf.get(b, 0, numBytes);
+            newbuf.limit(numBytes);
+            return newbuf;
+        } else {
+            // copy remainder of chunkbuf to newbuf and make newbuf chunkbuf
+            chunkbuf.mark();
+            chunkbuf.position(midpoint);
+            chunkbuf.get(b, 0, remainder);
+            chunkbuf.reset();
+            chunkbuf.limit(midpoint);
+            newbuf.limit(remainder);
+            newbuf.position(0);
+            ByteBuffer tmp = chunkbuf;
+            chunkbuf = newbuf;
+            return tmp;
+        }
+    }
+
+    private void pushBodyChunked(ByteBuffer b) throws IOException {
+        chunkbuf = b;
+        while (true) {
+            ByteBuffer b1 = readChunkedBuffer();
+            if (b1 != null) {
+                if (b1.hasRemaining()) {
+                    request(1); // wait till we can send
+                    pusher.onResponseBodyChunk(b1);
+                    lastBufferUsed = b1;
+                }
+            } else {
+                return;
+            }
+        }
+    }
+
+    private int toDigit(int b) throws IOException {
+        if (b >= 0x30 && b <= 0x39) {
+            return b - 0x30;
+        }
+        if (b >= 0x41 && b <= 0x46) {
+            return b - 0x41 + 10;
+        }
+        if (b >= 0x61 && b <= 0x66) {
+            return b - 0x61 + 10;
+        }
+        throw new IOException("Invalid chunk header byte " + b);
+    }
+
+    private void request(long value) throws IOException {
+        try {
+            flowController.request(value);
+        } catch (InterruptedException e) {
+            throw new IOException(e);
+        }
+    }
+
+    private void pushBodyFixed(ByteBuffer b) throws IOException {
+        lastBufferUsed = b;
+        for (int remaining = contentLength; remaining > 0;) {
+            int bufsize = b.remaining();
+            if (bufsize > remaining) {
+                // more data available than required, must copy
+                lastBufferUsed = b;
+                b = copyBuffer(b, remaining);
+                remaining = 0;
+            } else {
+                // pass entire buffer up to user
+                remaining -= bufsize;
+                compactBuffer(b);
+            }
+            request(1); // wait till we can send
+            pusher.onResponseBodyChunk(b);
+            if (remaining > 0) {
+                b = connection.read();
+                if (b == null) {
+                    throw new IOException("Error reading response");
+                }
+                lastBufferUsed = b;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,480 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Reads response headers off channel, in blocking mode. Entire header
+ * block is collected in a byte[]. The offset location of the start of
+ * each header name is recorded in an array to facilitate later searching.
+ *
+ * The location of "Content-length" is recorded explicitly. Similar approach
+ * could be taken for other common headers.
+ *
+ * This class is not thread-safe
+ */
+class ResponseHeaders implements HttpHeaders1 {
+
+    static final int DATA_SIZE = 16 * 1024;  // initial space for headers
+    static final int NUM_HEADERS = 50; // initial expected max number of headers
+
+    final HttpConnection connection;
+    byte[] data;
+    int contentlen = -2; // means not initialized
+    ByteBuffer buffer;
+
+    /**
+     * Following used for scanning the array looking for:
+     *      - well known headers
+     *      - end of header block
+     */
+    int[] headerOffsets; // index into data
+    int numHeaders;
+    int count;
+
+    ByteBuffer residue; // after headers processed, data may be here
+
+    ResponseHeaders(HttpConnection connection, ByteBuffer buffer) {
+        this.connection = connection;
+        initOffsets();
+        this.buffer = buffer;
+        data = new byte[DATA_SIZE];
+    }
+
+    int getContentLength() throws IOException {
+        if (contentlen != -2) {
+            return contentlen;
+        }
+        int[] search = findHeaderValue("Content-length");
+        if (search[0] == -1) {
+            contentlen = -1;
+            return -1;
+        }
+
+        int i = search[0];
+
+        while (data[i] == ' ' || data[i] == '\t') {
+            i++;
+            if (i == data.length || data[i] == CR || data[i] == LF) {
+                throw new IOException("Bad header");
+            }
+        }
+        contentlen = 0;
+        int digit = data[i++] - 0x30;
+        while (digit >= 0 && digit <= 9) {
+            contentlen = contentlen * 10 + digit;
+            digit = data[i++] - 0x30;
+        }
+        return contentlen;
+    }
+
+    void log() {
+        populateMap(false);
+    }
+
+    void  populateMap(boolean clearOffsets) {
+        StringBuilder sb;
+
+        for (int i = 0; i < numHeaders; i++) {
+            sb = new StringBuilder(32);
+            int offset = headerOffsets[i];
+            if (offset == -1) {
+                continue;
+            }
+            int j;
+            for (j=0; data[offset+j] != ':'; j++) {
+                // byte to char promotion ok for US-ASCII
+                sb.append((char)data[offset+j]);
+            }
+            String name = sb.toString();
+            List<String> l = getOrCreate(name);
+            addEntry(l, name, offset + j + 1);
+            // clear the offset
+            if (clearOffsets)
+                headerOffsets[i] = -1;
+        }
+    }
+
+    void addEntry(List<String> l, String name, int j) {
+
+        while (data[j] == ' ' || data[j] == '\t') {
+            j++;
+        }
+
+        int vstart = j;
+            // TODO: back slash ??
+
+        while (data[j] != CR) {
+            j++;
+        }
+        try {
+            String value = new String(data, vstart, j - vstart, "US-ASCII");
+            l.add(value);
+        } catch (UnsupportedEncodingException e) {
+            // can't happen
+            throw new InternalError(e);
+        }
+    }
+
+    // returns an int[2]: [0] = offset of value in data[]
+    // [1] = offset in headerOffsets. Both are -1 in error
+
+    private int[] findHeaderValue(String name) {
+        int[] result = new int[2];
+        byte[] namebytes = getBytes(name);
+
+ outer: for (int i = 0; i < numHeaders; i++) {
+            int offset = headerOffsets[i];
+            if (offset == -1) {
+                continue;
+            }
+
+            for (int j=0; j<namebytes.length; j++) {
+                if (namebytes[j] != lowerCase(data[offset+j])) {
+                    continue outer;
+                }
+            }
+            // next char must be ':'
+            if (data[offset+namebytes.length] != ':') {
+                continue;
+            }
+            result[0] = offset+namebytes.length + 1;
+            result[1] = i;
+            return result;
+        }
+        result[0] = -1;
+        result[1] = -1;
+        return result;
+    }
+
+    /**
+     * Populates the map for header values with the given name.
+     * The offsets are cleared for any that are found, so they don't
+     * get repeatedly searched.
+     */
+    List<String> populateMapEntry(String name) {
+        List<String> l = getOrCreate(name);
+        int[] search = findHeaderValue(name);
+        if (search[0] != -1) {
+            addEntry(l, name, search[0]);
+            // clear the offset
+            headerOffsets[search[1]] = -1;
+        }
+        return l;
+    }
+
+    static final Locale usLocale = Locale.US;
+    static final Charset ascii = StandardCharsets.US_ASCII;
+
+    private byte[] getBytes(String name) {
+        return name.toLowerCase(usLocale).getBytes(ascii);
+    }
+
+    /*
+     * We read buffers in a loop until we detect end of headers
+     * CRLFCRLF. Each byte received is copied into the byte[] data
+     * The position of the first byte of each header (after a CRLF)
+     * is recorded in a separate array showing the location of
+     * each header name.
+     */
+    void initHeaders() throws IOException {
+
+        inHeaderName = true;
+        endOfHeader = true;
+
+        for (int numBuffers = 0; true; numBuffers++) {
+
+            if (numBuffers > 0) {
+                buffer = connection.read();
+            }
+
+            if (buffer == null) {
+                throw new IOException("Error reading headers");
+            }
+
+            if (!buffer.hasRemaining()) {
+                continue;
+            }
+
+            // Position set to first byte
+            int start = buffer.position();
+            byte[] backing = buffer.array();
+            int len = buffer.limit() - start;
+
+            for (int i = 0; i < len; i++) {
+                byte b = backing[i + start];
+                if (inHeaderName) {
+                    b = lowerCase(b);
+                }
+                if (b == ':') {
+                    inHeaderName = false;
+                }
+                data[count++] = b;
+                checkByte(b);
+                if (firstChar) {
+                    recordHeaderOffset(count-1);
+                    firstChar = false;
+                }
+                if (endOfHeader && numHeaders == 0) {
+                    // empty headers
+                    endOfAllHeaders = true;
+                }
+                if (endOfAllHeaders) {
+                    int newposition = i + 1 + start;
+                    if (newposition <= buffer.limit()) {
+                        buffer.position(newposition);
+                        residue = buffer;
+                    } else {
+                        residue = null;
+                    }
+                    return;
+                }
+
+                if (count == data.length) {
+                    resizeData();
+                }
+            }
+        }
+    }
+
+    static final int CR = 13;
+    static final int LF = 10;
+    int crlfCount = 0;
+
+    // results of checkByte()
+    boolean endOfHeader; // just seen LF after CR before
+    boolean endOfAllHeaders; // just seen LF after CRLFCR before
+    boolean firstChar; //
+    boolean inHeaderName; // examining header name
+
+    void checkByte(byte b) throws IOException {
+        if (endOfHeader &&  b != CR && b != LF)
+            firstChar = true;
+        endOfHeader = false;
+        endOfAllHeaders = false;
+        switch (crlfCount) {
+            case 0:
+                crlfCount = b == CR ? 1 : 0;
+                break;
+            case 1:
+                crlfCount = b == LF ? 2 : 0;
+                endOfHeader = true;
+                inHeaderName = true;
+                break;
+            case 2:
+                crlfCount = b == CR ? 3 : 0;
+                break;
+            case 3:
+                if (b != LF) {
+                    throw new IOException("Bad header block termination");
+                }
+                endOfAllHeaders = true;
+                break;
+        }
+    }
+
+    byte lowerCase(byte b) {
+        if (b >= 0x41 && b <= 0x5A)
+            b = (byte)(b + 32);
+        return b;
+    }
+
+    void resizeData() {
+        int oldlen = data.length;
+        int newlen = oldlen * 2;
+        byte[] newdata = new byte[newlen];
+        System.arraycopy(data, 0, newdata, 0, oldlen);
+        data = newdata;
+    }
+
+    final void initOffsets() {
+        headerOffsets = new int[NUM_HEADERS];
+        numHeaders = 0;
+    }
+
+    ByteBuffer getResidue() {
+        return residue;
+    }
+
+    void recordHeaderOffset(int index) {
+        if (numHeaders >= headerOffsets.length) {
+            int oldlen = headerOffsets.length;
+            int newlen = oldlen * 2;
+            int[] new1 = new int[newlen];
+            System.arraycopy(headerOffsets, 0, new1, 0, oldlen);
+            headerOffsets = new1;
+        }
+        headerOffsets[numHeaders++] = index;
+    }
+
+    /**
+     * As entries are read from the byte[] they are placed in here
+     * So we always check this map first
+     */
+    Map<String,List<String>> headers = new HashMap<>();
+
+    @Override
+    public Optional<String> firstValue(String name) {
+        List<String> l =  allValues(name);
+        if (l == null || l.isEmpty()) {
+            return Optional.ofNullable(null);
+        } else {
+            return Optional.of(l.get(0));
+        }
+    }
+
+    @Override
+    public List<String> allValues(String name) {
+        name = name.toLowerCase(usLocale);
+        List<String> l = headers.get(name);
+        if (l == null) {
+            l = populateMapEntry(name);
+        }
+        return Collections.unmodifiableList(l);
+    }
+
+    @Override
+    public void makeUnmodifiable() {
+    }
+
+    // Delegates map to HashMap but converts keys to lower case
+
+    static class HeaderMap implements Map<String,List<String>> {
+        Map<String,List<String>> inner;
+
+        HeaderMap(Map<String,List<String>> inner) {
+            this.inner = inner;
+        }
+        @Override
+        public int size() {
+            return inner.size();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return inner.isEmpty();
+        }
+
+        @Override
+        public boolean containsKey(Object key) {
+            if (!(key instanceof String)) {
+                return false;
+            }
+            String s = ((String)key).toLowerCase(usLocale);
+            return inner.containsKey(s);
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            return inner.containsValue(value);
+        }
+
+        @Override
+        public List<String> get(Object key) {
+            String s = ((String)key).toLowerCase(usLocale);
+            return inner.get(s);
+        }
+
+        @Override
+        public List<String> put(String key, List<String> value) {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public List<String> remove(Object key) {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public void putAll(Map<? extends String, ? extends List<String>> m) {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public void clear() {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public Set<String> keySet() {
+            return inner.keySet();
+        }
+
+        @Override
+        public Collection<List<String>> values() {
+            return inner.values();
+        }
+
+        @Override
+        public Set<Entry<String, List<String>>> entrySet() {
+            return inner.entrySet();
+        }
+    }
+
+    @Override
+    public Map<String, List<String>> map() {
+        populateMap(true);
+        return new HeaderMap(headers);
+    }
+
+    Map<String, List<String>> mapInternal() {
+        populateMap(false);
+        return new HeaderMap(headers);
+    }
+
+    private List<String> getOrCreate(String name) {
+        List<String> l = headers.get(name);
+        if (l == null) {
+            l = new LinkedList<>();
+            headers.put(name, l);
+        }
+        return l;
+    }
+
+    @Override
+    public Optional<Long> firstValueAsLong(String name) {
+        List<String> l =  allValues(name);
+        if (l == null) {
+            return Optional.ofNullable(null);
+        } else {
+            String v = l.get(0);
+            Long lv = Long.parseLong(v);
+            return Optional.of(lv);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,178 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLParameters;
+import java.net.http.SSLDelegate.BufType;
+import java.net.http.SSLDelegate.WrapperResult;
+
+/**
+ * An SSL connection built on a Plain TCP connection.
+ */
+class SSLConnection extends HttpConnection {
+
+    PlainHttpConnection delegate;
+    SSLDelegate sslDelegate;
+    final String[] alpn;
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        return delegate.connectAsync()
+                .thenCompose((Void v) -> {
+                    CompletableFuture<Void> cf = new CompletableFuture<>();
+                    try {
+                        this.sslDelegate = new SSLDelegate(delegate.channel(),
+                                                           client,
+                                                           alpn);
+                        cf.complete(null);
+                    } catch (IOException e) {
+                        cf.completeExceptionally(e);
+                    }
+                    return cf;
+                });
+    }
+
+    @Override
+    public void connect() throws IOException {
+        delegate.connect();
+        this.sslDelegate = new SSLDelegate(delegate.channel(), client, alpn);
+    }
+
+    SSLConnection(InetSocketAddress addr, HttpClientImpl client, String[] ap) {
+        super(addr, client);
+        this.alpn = ap;
+        delegate = new PlainHttpConnection(addr, client);
+    }
+
+    @Override
+    SSLParameters sslParameters() {
+        return sslDelegate.getSSLParameters();
+    }
+
+    @Override
+    public String toString() {
+        return "SSLConnection: " + super.toString();
+    }
+
+    private static long countBytes(ByteBuffer[] buffers, int start, int length) {
+        long c = 0;
+        for (int i=0; i<length; i++) {
+            c+= buffers[start+i].remaining();
+        }
+        return c;
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return ConnectionPool.cacheKey(address, null);
+    }
+
+    @Override
+    long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        //debugPrint("Send", buffers, start, number);
+        long l = countBytes(buffers, start, number);
+        WrapperResult r = sslDelegate.sendData(buffers, start, number);
+        if (r.result.getStatus() == Status.CLOSED) {
+            if (l > 0) {
+                throw new IOException("SSLHttpConnection closed");
+            }
+        }
+        return l;
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        //debugPrint("Send", buffer);
+        long l = buffer.remaining();
+        WrapperResult r = sslDelegate.sendData(buffer);
+        if (r.result.getStatus() == Status.CLOSED) {
+            if (l > 0) {
+                throw new IOException("SSLHttpConnection closed");
+            }
+        }
+        return l;
+    }
+
+    @Override
+    void close() {
+        try {
+            //System.err.println ("Closing: " + this);
+            delegate.channel().close(); // TODO: proper close
+        } catch (IOException ex) {
+            Log.logError(ex.toString());
+        }
+    }
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        ByteBuffer buf = sslDelegate.allocate(BufType.PACKET, length);
+        WrapperResult r = sslDelegate.recvData(buf);
+        // TODO: check for closure
+        String s = "Receive) ";
+        //debugPrint(s, r.buf);
+        return r.buf;
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buf) throws IOException {
+        // TODO: need to ensure that buf is big enough for application data
+        WrapperResult r = sslDelegate.recvData(buf);
+        // TODO: check for closure
+        String s = "Receive) ";
+        //debugPrint(s, r.buf);
+        return r.result.bytesProduced();
+    }
+
+    @Override
+    boolean connected() {
+        return delegate.connected();
+    }
+
+    @Override
+    SocketChannel channel() {
+        return delegate.channel();
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        return delegate.whenReceivingResponse();
+    }
+
+    @Override
+    boolean isSecure() {
+        return true;
+    }
+
+    @Override
+    boolean isProxied() {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,457 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.Arrays;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
+
+/**
+ * Implements the mechanics of SSL by managing an SSLEngine object.
+ * One of these is associated with each SSLConnection.
+ */
+class SSLDelegate {
+
+    final SSLEngine engine;
+    final EngineWrapper wrapper;
+    final Lock handshaking = new ReentrantLock();
+    final SSLParameters sslParameters;
+    final SocketChannel chan;
+    final HttpClientImpl client;
+
+    // alpn[] may be null
+    SSLDelegate(SocketChannel chan, HttpClientImpl client, String[] alpn)
+        throws IOException
+    {
+        SSLContext context = client.sslContext();
+        engine = context.createSSLEngine();
+        engine.setUseClientMode(true);
+        SSLParameters sslp = client.sslParameters().orElse(null);
+        if (sslp == null) {
+            sslp = context.getDefaultSSLParameters();
+        }
+        sslParameters = Utils.copySSLParameters(sslp);
+        if (alpn != null) {
+            sslParameters.setApplicationProtocols(alpn);
+            Log.logSSL("Setting application protocols: " + Arrays.toString(alpn));
+        } else {
+            Log.logSSL("Warning no application protocols proposed!");
+        }
+        engine.setSSLParameters(sslParameters);
+        wrapper = new EngineWrapper(chan, engine);
+        this.chan = chan;
+        this.client = client;
+    }
+
+    SSLParameters getSSLParameters() {
+        return sslParameters;
+    }
+
+    private static long countBytes(ByteBuffer[] buffers, int start, int number) {
+        long c = 0;
+        for (int i=0; i<number; i++) {
+            c+= buffers[start+i].remaining();
+        }
+        return c;
+    }
+
+
+    static class WrapperResult {
+        static WrapperResult createOK() {
+            WrapperResult r = new WrapperResult();
+            r.buf = null;
+            r.result = new SSLEngineResult(Status.OK, NOT_HANDSHAKING, 0, 0);
+            return r;
+        }
+        SSLEngineResult result;
+
+        /* if passed in buffer was not big enough then the a reallocated buffer
+         * is returned here  */
+        ByteBuffer buf;
+    }
+
+    int app_buf_size;
+    int packet_buf_size;
+
+    enum BufType {
+        PACKET,
+        APPLICATION
+    };
+
+    ByteBuffer allocate (BufType type) {
+        return allocate (type, -1);
+    }
+
+    // TODO: Use buffer pool for this
+    ByteBuffer allocate (BufType type, int len) {
+        assert engine != null;
+        synchronized (this) {
+            int size;
+            if (type == BufType.PACKET) {
+                if (packet_buf_size == 0) {
+                    SSLSession sess = engine.getSession();
+                    packet_buf_size = sess.getPacketBufferSize();
+                }
+                if (len > packet_buf_size) {
+                    packet_buf_size = len;
+                }
+                size = packet_buf_size;
+            } else {
+                if (app_buf_size == 0) {
+                    SSLSession sess = engine.getSession();
+                    app_buf_size = sess.getApplicationBufferSize();
+                }
+                if (len > app_buf_size) {
+                    app_buf_size = len;
+                }
+                size = app_buf_size;
+            }
+            return ByteBuffer.allocate (size);
+        }
+    }
+
+    /* reallocates the buffer by :-
+     * 1. creating a new buffer double the size of the old one
+     * 2. putting the contents of the old buffer into the new one
+     * 3. set xx_buf_size to the new size if it was smaller than new size
+     *
+     * flip is set to true if the old buffer needs to be flipped
+     * before it is copied.
+     */
+    private ByteBuffer realloc (ByteBuffer b, boolean flip, BufType type) {
+        synchronized (this) {
+            int nsize = 2 * b.capacity();
+            ByteBuffer n = allocate (type, nsize);
+            if (flip) {
+                b.flip();
+            }
+            n.put(b);
+            b = n;
+        }
+        return b;
+    }
+
+    /**
+     * This is a thin wrapper over SSLEngine and the SocketChannel, which
+     * guarantees the ordering of wraps/unwraps with respect to the underlying
+     * channel read/writes. It handles the UNDER/OVERFLOW status codes
+     * It does not handle the handshaking status codes, or the CLOSED status code
+     * though once the engine is closed, any attempt to read/write to it
+     * will get an exception.  The overall result is returned.
+     * It functions synchronously/blocking
+     */
+    class EngineWrapper {
+
+        SocketChannel chan;
+        SSLEngine engine;
+        Object wrapLock, unwrapLock;
+        ByteBuffer unwrap_src, wrap_dst;
+        boolean closed = false;
+        int u_remaining; // the number of bytes left in unwrap_src after an unwrap()
+
+        EngineWrapper (SocketChannel chan, SSLEngine engine) throws IOException {
+            this.chan = chan;
+            this.engine = engine;
+            wrapLock = new Object();
+            unwrapLock = new Object();
+            unwrap_src = allocate(BufType.PACKET);
+            wrap_dst = allocate(BufType.PACKET);
+        }
+
+        void close () throws IOException {
+        }
+
+        WrapperResult wrapAndSend(ByteBuffer src, boolean ignoreClose)
+            throws IOException
+        {
+            ByteBuffer[] buffers = new ByteBuffer[1];
+            buffers[0] = src;
+            return wrapAndSend(buffers, 0, 1, ignoreClose);
+        }
+
+        /* try to wrap and send the data in src. Handles OVERFLOW.
+         * Might block if there is an outbound blockage or if another
+         * thread is calling wrap(). Also, might not send any data
+         * if an unwrap is needed.
+         */
+        WrapperResult wrapAndSend(ByteBuffer[] src,
+                                  int offset,
+                                  int len,
+                                  boolean ignoreClose)
+            throws IOException
+        {
+            if (closed && !ignoreClose) {
+                throw new IOException ("Engine is closed");
+            }
+            Status status;
+            WrapperResult r = new WrapperResult();
+            synchronized (wrapLock) {
+                wrap_dst.clear();
+                do {
+                    r.result = engine.wrap (src, offset, len, wrap_dst);
+                    status = r.result.getStatus();
+                    if (status == Status.BUFFER_OVERFLOW) {
+                        wrap_dst = realloc (wrap_dst, true, BufType.PACKET);
+                    }
+                } while (status == Status.BUFFER_OVERFLOW);
+                if (status == Status.CLOSED && !ignoreClose) {
+                    closed = true;
+                    return r;
+                }
+                if (r.result.bytesProduced() > 0) {
+                    wrap_dst.flip();
+                    int l = wrap_dst.remaining();
+                    assert l == r.result.bytesProduced();
+                    while (l>0) {
+                        l -= chan.write (wrap_dst);
+                    }
+                }
+            }
+            return r;
+        }
+
+        /* block until a complete message is available and return it
+         * in dst, together with the Result. dst may have been re-allocated
+         * so caller should check the returned value in Result
+         * If handshaking is in progress then, possibly no data is returned
+         */
+        WrapperResult recvAndUnwrap(ByteBuffer dst) throws IOException {
+            Status status;
+            WrapperResult r = new WrapperResult();
+            r.buf = dst;
+            if (closed) {
+                throw new IOException ("Engine is closed");
+            }
+            boolean needData;
+            if (u_remaining > 0) {
+                unwrap_src.compact();
+                unwrap_src.flip();
+                needData = false;
+            } else {
+                unwrap_src.clear();
+                needData = true;
+            }
+            synchronized (unwrapLock) {
+                int x;
+                do {
+                    if (needData) {
+                        do {
+                        x = chan.read (unwrap_src);
+                        } while (x == 0);
+                        if (x == -1) {
+                            throw new IOException ("connection closed for reading");
+                        }
+                        unwrap_src.flip();
+                    }
+                    r.result = engine.unwrap (unwrap_src, r.buf);
+                    status = r.result.getStatus();
+                    if (status == Status.BUFFER_UNDERFLOW) {
+                        if (unwrap_src.limit() == unwrap_src.capacity()) {
+                            /* buffer not big enough */
+                            unwrap_src = realloc (
+                                unwrap_src, false, BufType.PACKET
+                            );
+                        } else {
+                            /* Buffer not full, just need to read more
+                             * data off the channel. Reset pointers
+                             * for reading off SocketChannel
+                             */
+                            unwrap_src.position (unwrap_src.limit());
+                            unwrap_src.limit (unwrap_src.capacity());
+                        }
+                        needData = true;
+                    } else if (status == Status.BUFFER_OVERFLOW) {
+                        r.buf = realloc (r.buf, true, BufType.APPLICATION);
+                        needData = false;
+                    } else if (status == Status.CLOSED) {
+                        closed = true;
+                        r.buf.flip();
+                        return r;
+                    }
+                } while (status != Status.OK);
+            }
+            u_remaining = unwrap_src.remaining();
+            return r;
+        }
+    }
+
+    WrapperResult sendData (ByteBuffer src) throws IOException {
+        ByteBuffer[] buffers = new ByteBuffer[1];
+        buffers[0] = src;
+        return sendData(buffers, 0, 1);
+    }
+
+    /**
+     * send the data in the given ByteBuffer. If a handshake is needed
+     * then this is handled within this method. When this call returns,
+     * all of the given user data has been sent and any handshake has been
+     * completed. Caller should check if engine has been closed.
+     */
+    WrapperResult sendData (ByteBuffer[] src, int offset, int len) throws IOException {
+        WrapperResult r = WrapperResult.createOK();
+        while (countBytes(src, offset, len) > 0) {
+            r = wrapper.wrapAndSend(src, offset, len, false);
+            Status status = r.result.getStatus();
+            if (status == Status.CLOSED) {
+                doClosure ();
+                return r;
+            }
+            HandshakeStatus hs_status = r.result.getHandshakeStatus();
+            if (hs_status != HandshakeStatus.FINISHED &&
+                hs_status != HandshakeStatus.NOT_HANDSHAKING)
+            {
+                doHandshake(hs_status);
+            }
+        }
+        return r;
+    }
+
+    /**
+     * read data thru the engine into the given ByteBuffer. If the
+     * given buffer was not large enough, a new one is allocated
+     * and returned. This call handles handshaking automatically.
+     * Caller should check if engine has been closed.
+     */
+    WrapperResult recvData (ByteBuffer dst) throws IOException {
+        /* we wait until some user data arrives */
+        int mark = dst.position();
+        WrapperResult r = null;
+        assert dst.position() == 0;
+        while (dst.position() == 0) {
+            r = wrapper.recvAndUnwrap (dst);
+            dst = (r.buf != dst) ? r.buf: dst;
+            Status status = r.result.getStatus();
+            if (status == Status.CLOSED) {
+                doClosure ();
+                return r;
+            }
+
+            HandshakeStatus hs_status = r.result.getHandshakeStatus();
+            if (hs_status != HandshakeStatus.FINISHED &&
+                hs_status != HandshakeStatus.NOT_HANDSHAKING)
+            {
+                doHandshake (hs_status);
+            }
+        }
+        Utils.flipToMark(dst, mark);
+        return r;
+    }
+
+    /* we've received a close notify. Need to call wrap to send
+     * the response
+     */
+    void doClosure () throws IOException {
+        try {
+            handshaking.lock();
+            ByteBuffer tmp = allocate(BufType.APPLICATION);
+            WrapperResult r;
+            do {
+                tmp.clear();
+                tmp.flip ();
+                r = wrapper.wrapAndSend(tmp, true);
+            } while (r.result.getStatus() != Status.CLOSED);
+        } finally {
+            handshaking.unlock();
+        }
+    }
+
+    /* do the (complete) handshake after acquiring the handshake lock.
+     * If two threads call this at the same time, then we depend
+     * on the wrapper methods being idempotent. eg. if wrapAndSend()
+     * is called with no data to send then there must be no problem
+     */
+    @SuppressWarnings("fallthrough")
+    void doHandshake (HandshakeStatus hs_status) throws IOException {
+        boolean wasBlocking = false;
+        try {
+            wasBlocking = chan.isBlocking();
+            handshaking.lock();
+            chan.configureBlocking(true);
+            ByteBuffer tmp = allocate(BufType.APPLICATION);
+            while (hs_status != HandshakeStatus.FINISHED &&
+                   hs_status != HandshakeStatus.NOT_HANDSHAKING)
+            {
+                WrapperResult r = null;
+                switch (hs_status) {
+                    case NEED_TASK:
+                        Runnable task;
+                        while ((task = engine.getDelegatedTask()) != null) {
+                            /* run in current thread, because we are already
+                             * running an external Executor
+                             */
+                            task.run();
+                        }
+                        /* fall thru - call wrap again */
+                    case NEED_WRAP:
+                        tmp.clear();
+                        tmp.flip();
+                        r = wrapper.wrapAndSend(tmp, false);
+                        break;
+
+                    case NEED_UNWRAP:
+                        tmp.clear();
+                        r = wrapper.recvAndUnwrap (tmp);
+                        if (r.buf != tmp) {
+                            tmp = r.buf;
+                        }
+                        assert tmp.position() == 0;
+                        break;
+                }
+                hs_status = r.result.getHandshakeStatus();
+            }
+            Log.logSSL(getSessionInfo());
+            if (!wasBlocking) {
+                chan.configureBlocking(false);
+            }
+        } finally {
+            handshaking.unlock();
+        }
+    }
+
+    String getSessionInfo() {
+        StringBuilder sb = new StringBuilder();
+        String application = engine.getApplicationProtocol();
+        SSLSession sess = engine.getSession();
+        String cipher = sess.getCipherSuite();
+        String protocol = sess.getProtocol();
+        sb.append("Handshake complete alpn: ")
+                .append(application)
+                .append(", Cipher: ")
+                .append(cipher)
+                .append(", Protocol: ")
+                .append(protocol);
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,179 @@
+/*
+ * 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
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.security.AccessControlContext;
+import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLParameters;
+import java.net.http.SSLDelegate.BufType;
+import java.net.http.SSLDelegate.WrapperResult;
+
+/**
+ * An SSL tunnel built on a Plain (CONNECT) TCP tunnel.
+ */
+class SSLTunnelConnection extends HttpConnection {
+
+    final PlainTunnelingConnection delegate;
+    protected SSLDelegate sslDelegate;
+    private volatile boolean connected;
+
+    @Override
+    public void connect() throws IOException, InterruptedException {
+        delegate.connect();
+        this.sslDelegate = new SSLDelegate(delegate.channel(), client, null);
+        connected = true;
+    }
+
+    @Override
+    boolean connected() {
+        return connected && delegate.connected();
+    }
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        return delegate.connectAsync()
+            .thenAccept((Void v) -> {
+                try {
+                    // can this block?
+                    this.sslDelegate = new SSLDelegate(delegate.channel(),
+                                                       client,
+                                                       null);
+                    connected = true;
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
+                }
+            });
+    }
+
+    SSLTunnelConnection(InetSocketAddress addr,
+                        HttpClientImpl client,
+                        InetSocketAddress proxy,
+                        AccessControlContext acc) {
+        super(addr, client);
+        delegate = new PlainTunnelingConnection(addr, proxy, client, acc);
+    }
+
+    @Override
+    SSLParameters sslParameters() {
+        return sslDelegate.getSSLParameters();
+    }
+
+    @Override
+    public String toString() {
+        return "SSLTunnelConnection: " + super.toString();
+    }
+
+    private static long countBytes(ByteBuffer[] buffers, int start, int number) {
+        long c = 0;
+        for (int i=0; i<number; i++) {
+            c+= buffers[start+i].remaining();
+        }
+        return c;
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return ConnectionPool.cacheKey(address, delegate.proxyAddr);
+    }
+
+    @Override
+    long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        //debugPrint("Send", buffers, start, number);
+        long l = countBytes(buffers, start, number);
+        WrapperResult r = sslDelegate.sendData(buffers, start, number);
+        if (r.result.getStatus() == Status.CLOSED) {
+            if (l > 0) {
+                throw new IOException("SSLHttpConnection closed");
+            }
+        }
+        return l;
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        //debugPrint("Send", buffer);
+        long l = buffer.remaining();
+        WrapperResult r = sslDelegate.sendData(buffer);
+        if (r.result.getStatus() == Status.CLOSED) {
+            if (l > 0) {
+                throw new IOException("SSLHttpConnection closed");
+            }
+        }
+        return l;
+    }
+
+    @Override
+    void close() {
+        try {
+            //System.err.println ("Closing: " + this);
+            delegate.channel().close(); // TODO: proper close
+        } catch (IOException ex) {
+        }
+    }
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        ByteBuffer buf = sslDelegate.allocate(BufType.PACKET, length);
+        WrapperResult r = sslDelegate.recvData(buf);
+        // TODO: check for closure
+        String s = "Receive) ";
+        //debugPrint(s, r.buf);
+        return r.buf;
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buf) throws IOException {
+        WrapperResult r = sslDelegate.recvData(buf);
+        // TODO: check for closure
+        String s = "Receive) ";
+        //debugPrint(s, r.buf);
+        return r.result.bytesProduced();
+    }
+
+    @Override
+    SocketChannel channel() {
+        return delegate.channel();
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        return delegate.whenReceivingResponse();
+    }
+
+    @Override
+    boolean isSecure() {
+        return true;
+    }
+
+    @Override
+    boolean isProxied() {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.function.LongConsumer;
+
+/**
+ * Http/2 Stream
+ */
+class Stream extends ExchangeImpl {
+
+    void debugPrint() {
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+            return null;
+    }
+
+    Stream(HttpClientImpl client, Http2Connection connection, Exchange e) {
+        super(e);
+    }
+
+    @Override
+    HttpResponseImpl getResponse() throws IOException {
+        return null;
+    }
+
+    @Override
+    void sendRequest() throws IOException, InterruptedException {
+    }
+
+    @Override
+    void sendHeadersOnly() throws IOException, InterruptedException {
+    }
+
+    @Override
+    void sendBody() throws IOException, InterruptedException {
+    }
+
+    @Override
+    CompletableFuture<Void> sendHeadersAsync() {
+        return null;
+    }
+
+    @Override
+    CompletableFuture<HttpResponseImpl> getResponseAsync(Void v) {
+        return null;
+    }
+
+    @Override
+    CompletableFuture<Void> sendBodyAsync() {
+        return null;
+    }
+
+    @Override
+    void cancel() {
+    }
+
+
+    @Override
+    CompletableFuture<Void> sendRequestAsync() {
+        return null;
+    }
+
+    @Override
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor) throws IOException {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/TimeoutEvent.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+/**
+ * Timeout event delivered by selector thread. Executes given handler
+ * if the timer not cancelled first.
+ *
+ * Register with HttpClientImpl.registerTimer(TimeoutEvent)
+ *
+ * Cancel with HttpClientImpl.cancelTimer(TimeoutEvent)
+ */
+abstract class TimeoutEvent {
+
+    final long timeval;
+
+    long delta; // used when on queue
+
+    TimeoutEvent(long timeval) { this.timeval = timeval; }
+
+    public abstract void handle();
+
+    /**  Returns the timevalue in milli-seconds */
+    public long timevalMillis() { return timeval; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,221 @@
+/*
+ * 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
+ */
+
+package java.net.http;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.net.NetPermission;
+import java.net.URI;
+import java.net.URLPermission;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.net.ssl.SSLParameters;
+import sun.net.NetProperties;
+
+/**
+ * Miscellaneous utilities
+ */
+class Utils {
+
+    /**
+     * Allocated buffer size. Must never be higher than 16K. But can be lower
+     * if smaller allocation units preferred. HTTP/2 mandates that all
+     * implementations support frame payloads of at least 16K.
+     */
+    public static final int BUFSIZE = 16 * 1024;
+
+    /** Validates a RFC7230 token */
+    static void validateToken(String token, String errormsg) {
+        int length = token.length();
+        for (int i = 0; i < length; i++) {
+            int c = token.codePointAt(i);
+            if (c >= 0x30 && c <= 0x39 // 0 - 9
+                    || (c >= 0x61 && c <= 0x7a) // a - z
+                    || (c >= 0x41 && c <= 0x5a) // A - Z
+                    || (c >= 0x21 && c <= 0x2e && c != 0x22 && c != 0x27 && c != 0x2c)
+                    || (c >= 0x5e && c <= 0x60)
+                    || (c == 0x7c) || (c == 0x7e)) {
+            } else {
+                throw new IllegalArgumentException(errormsg);
+            }
+        }
+    }
+
+    /**
+     * Return sthe security permission required for the given details.
+     * If method is CONNECT, then uri must be of form "scheme://host:port"
+     */
+    static URLPermission getPermission(URI uri,
+                                       String method,
+                                       Map<String, List<String>> headers) {
+        StringBuilder sb = new StringBuilder();
+
+        String urlstring, actionstring;
+
+        if (method.equals("CONNECT")) {
+            urlstring = uri.toString();
+            actionstring = "CONNECT";
+        } else {
+            sb.append(uri.getScheme())
+                    .append("://")
+                    .append(uri.getHost())
+                    .append(uri.getPath());
+            urlstring = sb.toString();
+
+            sb = new StringBuilder();
+            sb.append(method);
+            if (headers != null && !headers.isEmpty()) {
+                sb.append(':');
+                Set<String> keys = headers.keySet();
+                boolean first = true;
+                for (String key : keys) {
+                    if (!first) {
+                        sb.append(',');
+                    }
+                    sb.append(key);
+                    first = false;
+                }
+            }
+            actionstring = sb.toString();
+        }
+        return new URLPermission(urlstring, actionstring);
+    }
+
+    static void checkNetPermission(String target) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null)
+            return;
+        NetPermission np = new NetPermission(target);
+        sm.checkPermission(np);
+    }
+
+    static int getIntegerNetProperty(String name, int defaultValue) {
+        return AccessController.doPrivileged((PrivilegedAction<Integer>)() ->
+            NetProperties.getInteger(name, defaultValue) );
+    }
+
+    static String getNetProperty(String name) {
+        return AccessController.doPrivileged((PrivilegedAction<String>)() ->
+            NetProperties.get(name) );
+    }
+
+    static SSLParameters copySSLParameters(SSLParameters p) {
+        SSLParameters p1 = new SSLParameters();
+        p1.setAlgorithmConstraints(p.getAlgorithmConstraints());
+        p1.setCipherSuites(p.getCipherSuites());
+        p1.setEnableRetransmissions(p.getEnableRetransmissions());
+        p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm());
+        p1.setMaximumPacketSize(p.getMaximumPacketSize());
+        p1.setNeedClientAuth(p.getNeedClientAuth());
+        p1.setProtocols(p.getProtocols().clone());
+        p1.setSNIMatchers(p.getSNIMatchers());
+        p1.setServerNames(p.getServerNames());
+        p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder());
+        p1.setWantClientAuth(p.getWantClientAuth());
+        return p1;
+    }
+
+
+    /** Resumes reading into the given buffer. */
+    static void unflip(ByteBuffer buf) {
+        buf.position(buf.limit());
+        buf.limit(buf.capacity());
+    }
+
+    /**
+     * Set limit to position, and position to mark.
+     *
+     *
+     * @param buffer
+     * @param mark
+     */
+    static void flipToMark(ByteBuffer buffer, int mark) {
+        buffer.limit(buffer.position());
+        buffer.position(mark);
+    }
+
+    /** Compact and leave ready for reading. */
+    static void compact(List<ByteBuffer> buffers) {
+        for (ByteBuffer b : buffers) {
+            b.compact();
+            b.flip();
+        }
+    }
+
+    static String stackTrace(Throwable t) {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        String s = null;
+        try {
+            PrintStream p = new PrintStream(bos, true, "US-ASCII");
+            t.printStackTrace(p);
+            s = bos.toString("US-ASCII");
+        } catch (UnsupportedEncodingException ex) {
+            // can't happen
+        }
+        return s;
+    }
+
+    /** Copies as much of src to dst as possible. */
+    static void copy (ByteBuffer src, ByteBuffer dst) {
+        int srcLen = src.remaining();
+        int dstLen = dst.remaining();
+        if (srcLen > dstLen) {
+            int diff = srcLen - dstLen;
+            int limit = src.limit();
+            src.limit(limit - diff);
+            dst.put(src);
+            src.limit(limit);
+        } else {
+            dst.put(src);
+        }
+    }
+
+    static ByteBuffer copy(ByteBuffer src) {
+        ByteBuffer dst = ByteBuffer.allocate(src.remaining());
+        dst.put(src);
+        dst.flip();
+        return dst;
+    }
+
+    static String combine(String[] s) {
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        boolean first = true;
+        for (String s1 : s) {
+            if (!first) {
+                sb.append(", ");
+                first = false;
+            }
+            sb.append(s1);
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/package-info.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/**
+ * <h2>High level HTTP API</h2>
+ * This provides a high-level client interface to HTTP (versions 1.1 and 2).
+ * Synchronous and asynchronous (via
+ * {@link java.util.concurrent.CompletableFuture}) modes are provided. The main
+ * classes defined are:
+ * <ul>
+ *    <li>{@link java.net.http.HttpClient}</li>
+ *    <li>{@link java.net.http.HttpRequest}</li>
+ *    <li>{@link java.net.http.HttpResponse}</li>
+ * </ul>
+ *
+ * @since 9
+ */
+package java.net.http;
--- a/jdk/src/jdk.jdi/share/native/libdt_shmem/shmemBack.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/jdk.jdi/share/native/libdt_shmem/shmemBack.c	Wed Jul 05 21:24:14 2017 +0200
@@ -338,7 +338,7 @@
     return JDWPTRANSPORT_ERROR_NONE;
 }
 
-JNIEXPORT jint JNICALL
+jint JNICALL
 jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
                      jint version, jdwpTransportEnv** result)
 {
--- a/jdk/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c	Wed Jul 05 21:24:14 2017 +0200
@@ -784,7 +784,7 @@
     return JDWPTRANSPORT_ERROR_NONE;
 }
 
-JNIEXPORT jint JNICALL
+jint JNICALL
 jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
                      jint version, jdwpTransportEnv** result)
 {
--- a/jdk/src/jdk.localedata/share/classes/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/src/jdk.localedata/share/classes/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo	Wed Jul 05 21:24:14 2017 +0200
@@ -1,2 +1,2 @@
 sun.util.resources.provider.NonBaseLocaleDataMetaInfo
-sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo_jdk_localedata
+sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo
--- a/jdk/test/ProblemList.txt	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 21:24:14 2017 +0200
@@ -200,6 +200,9 @@
 java/nio/file/WatchService/Basic.java				solaris-all
 java/nio/file/WatchService/LotsOfEvents.java			solaris-all
 
+# 8149712
+java/nio/charset/coders/BashStreams.java                        generic-all
+
 ############################################################################
 
 # jdk_rmi
--- a/jdk/test/com/sun/net/httpserver/FileServerHandler.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/com/sun/net/httpserver/FileServerHandler.java	Wed Jul 05 21:24:14 2017 +0200
@@ -23,6 +23,7 @@
 
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.logging.*;
 import java.io.*;
 import java.net.*;
 import java.security.*;
@@ -36,6 +37,10 @@
  * Must be given an abs pathname to the document root.
  * Directory listings together with text + html files
  * can be served.
+ *
+ * File Server created on files sub-path
+ *
+ * Echo server created on echo sub-path
  */
 public class FileServerHandler implements HttpHandler {
 
@@ -44,14 +49,24 @@
                 System.out.println ("usage: java FileServerHandler rootDir port logfilename");
                 System.exit(1);
             }
+            Logger logger = Logger.getLogger("com.sun.net.httpserver");
+            ConsoleHandler ch = new ConsoleHandler();
+            logger.setLevel(Level.ALL);
+            ch.setLevel(Level.ALL);
+            logger.addHandler(ch);
+
             String rootDir = args[0];
             int port = Integer.parseInt (args[1]);
             String logfile = args[2];
-            HttpServer server = HttpServer.create (new InetSocketAddress (8000), 0);
+            HttpServer server = HttpServer.create (new InetSocketAddress (port), 0);
             HttpHandler h = new FileServerHandler (rootDir);
+            HttpHandler h1 = new EchoHandler ();
 
-            HttpContext c = server.createContext ("/", h);
+            HttpContext c = server.createContext ("/files", h);
             c.getFilters().add (new LogFilter (new File (logfile)));
+            HttpContext c1 = server.createContext ("/echo", h1);
+            c.getFilters().add (new LogFilter (new File (logfile)));
+            c1.getFilters().add (new LogFilter (new File (logfile)));
             server.setExecutor (Executors.newCachedThreadPool());
             server.start ();
         }
@@ -72,7 +87,8 @@
             URI uri = t.getRequestURI();
             String path = uri.getPath();
 
-            while (is.read () != -1) ;
+            int x = 0;
+            while (is.read () != -1) x++;
             is.close();
             File f = new File (docroot, path);
             if (!f.exists()) {
@@ -164,3 +180,61 @@
             t.close();
         }
     }
+
+class EchoHandler implements HttpHandler {
+
+    byte[] read(InputStream is) throws IOException {
+        byte[] buf = new byte[1024];
+        byte[] result = new byte[0];
+
+        while (true) {
+            int n = is.read(buf);
+            if (n > 0) {
+                byte[] b1 = new byte[result.length + n];
+                System.arraycopy(result, 0, b1, 0, result.length);
+                System.arraycopy(buf, 0, b1, result.length, n);
+                result = b1;
+            } else if (n == -1) {
+                return result;
+            }
+        }
+    }
+
+    public void handle (HttpExchange t)
+        throws IOException
+    {
+        InputStream is = t.getRequestBody();
+        Headers map = t.getRequestHeaders();
+        String fixedrequest = map.getFirst ("XFixed");
+
+        // return the number of bytes received (no echo)
+        String summary = map.getFirst ("XSummary");
+        if (fixedrequest != null && summary == null)  {
+            byte[] in = read(is);
+            t.sendResponseHeaders(200, in.length);
+            OutputStream os = t.getResponseBody();
+            os.write(in);
+            os.close();
+            is.close();
+        } else {
+            OutputStream os = t.getResponseBody();
+            byte[] buf = new byte[64 * 1024];
+            t.sendResponseHeaders(200, 0);
+            int n, count=0;;
+
+            while ((n = is.read(buf)) != -1) {
+                if (summary == null) {
+                    os.write(buf, 0, n);
+                }
+                count += n;
+            }
+            if (summary != null) {
+                String s = Integer.toString(count);
+                os.write(s.getBytes());
+            }
+            os.close();
+            is.close();
+        }
+    }
+}
+
--- a/jdk/test/java/lang/invoke/T8139885.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/lang/invoke/T8139885.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
 /* @test
  * @bug 8139885
  * @bug 8143798
+ * @bug 8150825
  * @run testng/othervm -ea -esa test.java.lang.invoke.T8139885
  */
 
@@ -315,14 +316,17 @@
                 {intid, MethodHandles.identity(double.class)},
                 {intid, MethodHandles.dropArguments(intid, 0, String.class)},
                 {intid, MethodHandles.dropArguments(intid, 0, Throwable.class, double.class)},
-                {errTarget, errCleanup}
+                {errTarget, errCleanup},
+                {TryFinally.MH_voidTarget, TryFinally.MH_voidCleanup}
         };
         String[] messages = {
                 "target and return types must match: double != int",
                 "cleanup first argument and Throwable must match: (String,int)int != class java.lang.Throwable",
                 "cleanup second argument and target return type must match: (Throwable,double,int)int != int",
                 "cleanup parameters after (Throwable,result) and target parameter list prefix must match: " +
-                        errCleanup.type() + " != " + errTarget.type()
+                        errCleanup.type() + " != " + errTarget.type(),
+                "cleanup parameters after (Throwable,result) and target parameter list prefix must match: " +
+                        TryFinally.MH_voidCleanup.type() + " != " + TryFinally.MH_voidTarget.type()
         };
         for (int i = 0; i < cases.length; ++i) {
             boolean caught = false;
@@ -908,6 +912,10 @@
             return r + " (but " + first + " first)!";
         }
 
+        static void voidTarget() {}
+
+        static void voidCleanup(Throwable t, int a) {}
+
         static final Class<TryFinally> TRY_FINALLY = TryFinally.class;
 
         static final MethodType MT_greet = methodType(String.class, String.class);
@@ -916,6 +924,8 @@
         static final MethodType MT_printMore = methodType(void.class, Throwable.class, String.class);
         static final MethodType MT_greetMore = methodType(String.class, String.class, String.class);
         static final MethodType MT_exclaimMore = methodType(String.class, Throwable.class, String.class, String.class);
+        static final MethodType MT_voidTarget = methodType(void.class);
+        static final MethodType MT_voidCleanup = methodType(void.class, Throwable.class, int.class);
 
         static final MethodHandle MH_greet;
         static final MethodHandle MH_exclaim;
@@ -923,6 +933,8 @@
         static final MethodHandle MH_printMore;
         static final MethodHandle MH_greetMore;
         static final MethodHandle MH_exclaimMore;
+        static final MethodHandle MH_voidTarget;
+        static final MethodHandle MH_voidCleanup;
 
         static final MethodType MT_hello = methodType(String.class, String.class);
         static final MethodType MT_printHello = methodType(void.class, String.class);
@@ -936,6 +948,8 @@
                 MH_printMore = LOOKUP.findStatic(TRY_FINALLY, "printMore", MT_printMore);
                 MH_greetMore = LOOKUP.findStatic(TRY_FINALLY, "greetMore", MT_greetMore);
                 MH_exclaimMore = LOOKUP.findStatic(TRY_FINALLY, "exclaimMore", MT_exclaimMore);
+                MH_voidTarget = LOOKUP.findStatic(TRY_FINALLY, "voidTarget", MT_voidTarget);
+                MH_voidCleanup = LOOKUP.findStatic(TRY_FINALLY, "voidCleanup", MT_voidCleanup);
             } catch (Exception e) {
                 throw new ExceptionInInitializerError(e);
             }
--- a/jdk/test/java/net/SocketOption/OptionsTest.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/net/SocketOption/OptionsTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -54,6 +54,7 @@
         Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
         Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
         Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
         Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(80)),
         Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
     };
@@ -61,6 +62,7 @@
     static Test[] serverSocketTests = new Test[] {
         Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
         Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
         Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
     };
 
@@ -68,6 +70,7 @@
         Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
         Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
         Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
         Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
     };
 
@@ -97,15 +100,19 @@
             Socket c = new Socket("127.0.0.1", srv.getLocalPort());
             Socket s = srv.accept();
         ) {
+            Set<SocketOption<?>> options = c.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
             for (int i=0; i<socketTests.length; i++) {
                 Test test = socketTests[i];
-                c.setOption((SocketOption)test.option, test.testValue);
-                Object getval = c.getOption((SocketOption)test.option);
-                Object legacyget = legacyGetOption(Socket.class, c,test.option);
-                if (!getval.equals(legacyget)) {
-                    Formatter f = new Formatter();
-                    f.format("S Err %d: %s/%s", i, getval, legacyget);
-                    throw new RuntimeException(f.toString());
+                if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
+                    c.setOption((SocketOption)test.option, test.testValue);
+                    Object getval = c.getOption((SocketOption)test.option);
+                    Object legacyget = legacyGetOption(Socket.class, c,test.option);
+                    if (!getval.equals(legacyget)) {
+                        Formatter f = new Formatter();
+                        f.format("S Err %d: %s/%s", i, getval, legacyget);
+                        throw new RuntimeException(f.toString());
+                    }
                 }
             }
         }
@@ -115,15 +122,19 @@
         try (
             DatagramSocket c = new DatagramSocket(0);
         ) {
+            Set<SocketOption<?>> options = c.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
             for (int i=0; i<dgSocketTests.length; i++) {
                 Test test = dgSocketTests[i];
-                c.setOption((SocketOption)test.option, test.testValue);
-                Object getval = c.getOption((SocketOption)test.option);
-                Object legacyget = legacyGetOption(DatagramSocket.class, c,test.option);
-                if (!getval.equals(legacyget)) {
-                    Formatter f = new Formatter();
-                    f.format("DG Err %d: %s/%s", i, getval, legacyget);
-                    throw new RuntimeException(f.toString());
+                if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
+                    c.setOption((SocketOption)test.option, test.testValue);
+                    Object getval = c.getOption((SocketOption)test.option);
+                    Object legacyget = legacyGetOption(DatagramSocket.class, c,test.option);
+                    if (!getval.equals(legacyget)) {
+                        Formatter f = new Formatter();
+                        f.format("DG Err %d: %s/%s", i, getval, legacyget);
+                        throw new RuntimeException(f.toString());
+                    }
                 }
             }
         }
@@ -151,17 +162,21 @@
         try (
             ServerSocket c = new ServerSocket(0);
         ) {
+            Set<SocketOption<?>> options = c.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
             for (int i=0; i<serverSocketTests.length; i++) {
                 Test test = serverSocketTests[i];
-                c.setOption((SocketOption)test.option, test.testValue);
-                Object getval = c.getOption((SocketOption)test.option);
-                Object legacyget = legacyGetOption(
-                    ServerSocket.class, c, test.option
-                );
-                if (!getval.equals(legacyget)) {
-                    Formatter f = new Formatter();
-                    f.format("SS Err %d: %s/%s", i, getval, legacyget);
-                    throw new RuntimeException(f.toString());
+                if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
+                    c.setOption((SocketOption)test.option, test.testValue);
+                    Object getval = c.getOption((SocketOption)test.option);
+                    Object legacyget = legacyGetOption(
+                        ServerSocket.class, c, test.option
+                    );
+                    if (!getval.equals(legacyget)) {
+                        Formatter f = new Formatter();
+                        f.format("SS Err %d: %s/%s", i, getval, legacyget);
+                        throw new RuntimeException(f.toString());
+                    }
                 }
             }
         }
@@ -174,6 +189,8 @@
     {
         if (type.equals(Socket.class)) {
             Socket socket = (Socket)s;
+            Set<SocketOption<?>> options = socket.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
 
             if (option.equals(StandardSocketOptions.SO_KEEPALIVE)) {
                 return Boolean.valueOf(socket.getKeepAlive());
@@ -183,6 +200,8 @@
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
+                return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
             } else if (option.equals(StandardSocketOptions.SO_LINGER)) {
                 return Integer.valueOf(socket.getSoLinger());
             } else if (option.equals(StandardSocketOptions.IP_TOS)) {
@@ -194,10 +213,15 @@
             }
         } else if  (type.equals(ServerSocket.class)) {
             ServerSocket socket = (ServerSocket)s;
+            Set<SocketOption<?>> options = socket.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
+
             if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
+                return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
             } else if (option.equals(StandardSocketOptions.IP_TOS)) {
                 return Integer.valueOf(jdk.net.Sockets.getOption(
                     socket, StandardSocketOptions.IP_TOS));
@@ -206,6 +230,8 @@
             }
         } else if  (type.equals(DatagramSocket.class)) {
             DatagramSocket socket = (DatagramSocket)s;
+            Set<SocketOption<?>> options = socket.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
 
             if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
                 return Integer.valueOf(socket.getSendBufferSize());
@@ -213,6 +239,8 @@
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
+                return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
             } else if (option.equals(StandardSocketOptions.IP_TOS)) {
                 return Integer.valueOf(socket.getTrafficClass());
             } else {
@@ -221,6 +249,8 @@
 
         } else if  (type.equals(MulticastSocket.class)) {
             MulticastSocket socket = (MulticastSocket)s;
+            Set<SocketOption<?>> options = socket.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
 
             if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
                 return Integer.valueOf(socket.getSendBufferSize());
@@ -228,6 +258,8 @@
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
+                return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
             } else if (option.equals(StandardSocketOptions.IP_TOS)) {
                 return Integer.valueOf(socket.getTrafficClass());
             } else if (option.equals(StandardSocketOptions.IP_MULTICAST_IF)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/APIErrors.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,207 @@
+/*
+ * 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 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @run main/othervm APIErrors
+ */
+//package javaapplication16;
+
+import com.sun.net.httpserver.*;
+import java.io.IOException;
+import java.net.*;
+import java.net.http.*;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.function.Supplier;
+
+/**
+ * Does stupid things with API, to check appropriate errors/exceptions thrown
+ */
+public class APIErrors {
+
+    static HttpServer s1 = null;
+    static ExecutorService executor = null;
+    static int port;
+    static HttpClient client;
+    static String httproot, fileuri, fileroot;
+    static List<HttpClient> clients = new LinkedList<>();
+
+    public static void main(String[] args) throws Exception {
+        initServer();
+        fileroot = System.getProperty("test.src") + "/docs";
+
+        client = HttpClient.create().build();
+
+        clients.add(HttpClient.getDefault());
+
+        try {
+            test1();
+            test2();
+            test3();
+        } finally {
+            s1.stop(0);
+            executor.shutdownNow();
+            for (HttpClient client : clients)
+                client.executorService().shutdownNow();
+        }
+    }
+
+    static void reject(Runnable r, Class<? extends Exception> extype) {
+        try {
+            r.run();
+            throw new RuntimeException("Expected: " + extype);
+        } catch (Throwable t) {
+            if (!extype.isAssignableFrom(t.getClass())) {
+                throw new RuntimeException("Wrong exception type: " + extype + " / "
+                    +t.getClass());
+            }
+        }
+    }
+
+    static void accept(Runnable r) {
+        try {
+            r.run();
+        } catch (Throwable t) {
+            throw new RuntimeException("Unexpected exception: " + t);
+        }
+    }
+
+    static void checkNonNull(Supplier<?> r) {
+        if (r.get() == null)
+            throw new RuntimeException("Unexpected null return:");
+    }
+
+    static void assertTrue(Supplier<Boolean> r) {
+        if (r.get() == false)
+            throw new RuntimeException("Assertion failure:");
+    }
+
+    // HttpClient.Builder
+    static void test1() throws Exception {
+        System.out.println("Test 1");
+        HttpClient.Builder cb = HttpClient.create();
+        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 5000);
+        reject(() -> { cb.priority(-1);}, IllegalArgumentException.class);
+        reject(() -> { cb.priority(500);}, IllegalArgumentException.class);
+        accept(() -> { cb.priority(1);});
+        accept(() -> { cb.priority(255);});
+
+        accept(() -> {clients.add(cb.build()); clients.add(cb.build());});
+    }
+
+    static void test2() throws Exception {
+        System.out.println("Test 2");
+        HttpClient.Builder cb = HttpClient.create();
+        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 5000);
+        cb.proxy(ProxySelector.of(addr));
+        HttpClient c = cb.build();
+        clients.add(c);
+        checkNonNull(()-> {return c.executorService();});
+        assertTrue(()-> {return c.followRedirects() == HttpClient.Redirect.NEVER;});
+        assertTrue(()-> {return !c.authenticator().isPresent();});
+    }
+
+    static URI accessibleURI() {
+        return URI.create(fileuri);
+    }
+
+    static HttpRequest request() {
+        return HttpRequest.create(accessibleURI())
+                .GET();
+    }
+
+    static void test3() throws Exception {
+        System.out.println("Test 3");
+        reject(()-> {
+            try {
+                HttpRequest r1 = request();
+                HttpResponse resp = r1.response();
+                HttpResponse resp1 = r1.response();
+            } catch (IOException |InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }, IllegalStateException.class);
+
+        reject(()-> {
+            try {
+                HttpRequest r1 = request();
+                HttpResponse resp = r1.response();
+                HttpResponse resp1 = r1.responseAsync().get();
+            } catch (IOException |InterruptedException | ExecutionException e) {
+                throw new RuntimeException(e);
+            }
+        }, IllegalStateException.class);
+        reject(()-> {
+            try {
+                HttpRequest r1 = request();
+                HttpResponse resp1 = r1.responseAsync().get();
+                HttpResponse resp = r1.response();
+            } catch (IOException |InterruptedException | ExecutionException e) {
+                throw new RuntimeException(e);
+            }
+        }, IllegalStateException.class);
+    }
+
+    static class Auth extends java.net.Authenticator {
+        int count = 0;
+        @Override
+        protected PasswordAuthentication getPasswordAuthentication() {
+            if (count++ == 0) {
+                return new PasswordAuthentication("user", "passwd".toCharArray());
+            } else {
+                return new PasswordAuthentication("user", "goober".toCharArray());
+            }
+        }
+        int count() {
+            return count;
+        }
+    }
+
+    public static void initServer() throws Exception {
+        String root = System.getProperty ("test.src")+ "/docs";
+        InetSocketAddress addr = new InetSocketAddress (0);
+        s1 = HttpServer.create (addr, 0);
+        if (s1 instanceof HttpsServer) {
+            throw new RuntimeException ("should not be httpsserver");
+        }
+        HttpHandler h = new FileServerHandler(root);
+
+        HttpContext c1 = s1.createContext("/files", h);
+
+        executor = Executors.newCachedThreadPool();
+        s1.setExecutor (executor);
+        s1.start();
+
+        port = s1.getAddress().getPort();
+        System.out.println("HTTP server port = " + port);
+        httproot = "http://127.0.0.1:" + port + "/files/";
+        fileuri = httproot + "foo.txt";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/BasicAuthTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,162 @@
+/*
+ * 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
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @run main/othervm BasicAuthTest
+ * @summary Basic Authentication Test
+ */
+
+import com.sun.net.httpserver.BasicAuthenticator;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.http.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+public class BasicAuthTest {
+
+    static volatile boolean ok;
+    static final String RESPONSE = "Hello world";
+    static final String POST_BODY = "This is the POST body 123909090909090";
+
+    public static void main(String[] args) throws Exception {
+        HttpServer server = HttpServer.create(new InetSocketAddress(0), 10);
+        ExecutorService e = Executors.newCachedThreadPool();
+        Handler h = new Handler();
+        HttpContext serverContext = server.createContext("/test", h);
+        int port = server.getAddress().getPort();
+        System.out.println("Server port = " + port);
+
+        ClientAuth ca = new ClientAuth();
+        ServerAuth sa = new ServerAuth("foo realm");
+        serverContext.setAuthenticator(sa);
+        server.setExecutor(e);
+        server.start();
+        HttpClient client = HttpClient.create()
+                                      .authenticator(ca)
+                                      .build();
+
+        try {
+            URI uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/test/foo");
+            HttpRequest req = client.request(uri).GET();
+
+            HttpResponse resp = req.response();
+            ok = resp.statusCode() == 200 &&
+                    resp.body(HttpResponse.asString()).equals(RESPONSE);
+
+            if (!ok || ca.count != 1)
+                throw new RuntimeException("Test failed");
+
+            // repeat same request, should succeed but no additional authenticator calls
+
+            req = client.request(uri).GET();
+            resp = req.response();
+            ok = resp.statusCode() == 200 &&
+                    resp.body(HttpResponse.asString()).equals(RESPONSE);
+
+            if (!ok || ca.count != 1)
+                throw new RuntimeException("Test failed");
+
+            // try a POST
+
+            req = client.request(uri)
+                    .body(HttpRequest.fromString(POST_BODY))
+                    .POST();
+            resp = req.response();
+            ok = resp.statusCode() == 200;
+
+            if (!ok || ca.count != 1)
+                throw new RuntimeException("Test failed");
+        } finally {
+            client.executorService().shutdownNow();
+            server.stop(0);
+            e.shutdownNow();
+        }
+        System.out.println("OK");
+    }
+
+    static class ServerAuth extends BasicAuthenticator {
+
+        ServerAuth(String realm) {
+            super(realm);
+        }
+
+        @Override
+        public boolean checkCredentials(String username, String password) {
+            if (!"user".equals(username) || !"passwd".equals(password)) {
+                return false;
+            }
+            return true;
+        }
+
+    }
+
+    static class ClientAuth extends java.net.Authenticator {
+        volatile int count = 0;
+
+        @Override
+        protected PasswordAuthentication getPasswordAuthentication() {
+            count++;
+            return new PasswordAuthentication("user", "passwd".toCharArray());
+        }
+    }
+
+   static class Handler implements HttpHandler {
+        static volatile boolean ok;
+
+        @Override
+        public void handle(HttpExchange he) throws IOException {
+            String method = he.getRequestMethod();
+            InputStream is = he.getRequestBody();
+            if (method.equalsIgnoreCase("POST")) {
+                String requestBody = new String(is.readAllBytes(), US_ASCII);
+                if (!requestBody.equals(POST_BODY)) {
+                    he.sendResponseHeaders(500, -1);
+                    ok = false;
+                } else {
+                    he.sendResponseHeaders(200, -1);
+                    ok = true;
+                }
+            } else { // GET
+                he.sendResponseHeaders(200, RESPONSE.length());
+                OutputStream os = he.getResponseBody();
+                os.write(RESPONSE.getBytes(US_ASCII));
+                os.close();
+                ok = true;
+            }
+        }
+
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/HeadersTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+import java.net.http.HttpRequest;
+import java.net.URI;
+
+/**
+ * @test
+ * @bug 8087112
+ * @summary Basic test for headers
+ */
+public class HeadersTest {
+
+    static final URI TEST_URI = URI.create("http://www.foo.com/");
+
+    static void bad(String name) {
+        HttpRequest.Builder builder = HttpRequest.create(TEST_URI);
+        try {
+            builder.header(name, "foo");
+            throw new RuntimeException("Expected IAE for header:" + name);
+        } catch (IllegalArgumentException expected) { }
+    }
+
+    static void good(String name) {
+        HttpRequest.Builder builder = HttpRequest.create(TEST_URI);
+        try {
+            builder.header(name, "foo");
+        } catch (IllegalArgumentException e) {
+            throw new RuntimeException("Unexpected IAE for header:" + name);
+        }
+    }
+
+    public static void main(String[] args) {
+        bad("bad:header");
+        bad("Foo\n");
+        good("X-Foo!");
+        good("Bar~");
+        good("x");
+        bad(" ");
+        bad("Bar\r\n");
+        good("Hello#world");
+        good("Qwer#ert");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/HttpUtils.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import static java.net.http.HttpRequest.fromByteArray;
+import static java.net.http.HttpRequest.fromByteArrays;
+import static java.net.http.HttpRequest.fromFile;
+import static java.net.http.HttpRequest.fromInputStream;
+import static java.net.http.HttpRequest.fromString;
+import java.net.http.HttpResponse;
+import static java.net.http.HttpResponse.asByteArray;
+import static java.net.http.HttpResponse.asFile;
+import static java.net.http.HttpResponse.asInputStream;
+import static java.net.http.HttpResponse.asString;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+public final class HttpUtils {
+
+    static final int DEFAULT_OFFSET = 10;
+    static final int DEFAULT_LENGTH = 1000;
+    static final String midSizedFilename = "/files/notsobigfile.txt";
+    static final String smallFilename = "/files/smallfile.txt";
+    static final Path midSizedFile;
+    static final Path smallFile;
+    static final String fileroot;
+
+    public enum RequestBody {
+        STRING, FILE, BYTE_ARRAY, BYTE_ARRAY_OFFSET, INPUTSTREAM, STRING_WITH_CHARSET,
+    }
+
+    static {
+        fileroot = System.getProperty("test.src") + "/docs";
+        midSizedFile = Paths.get(fileroot + midSizedFilename);
+        smallFile = Paths.get(fileroot + smallFilename);
+    }
+
+    static public String getFileContent(String path) throws IOException {
+        FileInputStream fis = new FileInputStream(path);
+        byte[] buf = new byte[2 * 1024];
+        StringBuilder sb = new StringBuilder();
+        int byteRead;
+        while ((byteRead = fis.read(buf)) != -1) {
+            sb.append(new String(buf, 0, byteRead, "US-ASCII"));
+        }
+        return sb.toString();
+    }
+
+    public static HttpRequest.Builder getHttpRequestBuilder(final HttpClient client,
+                                                            final String requestType,
+                                                            final URI uri)
+        throws IOException
+    {
+        HttpRequest.Builder builder;
+        String filename = smallFile.toFile().getAbsolutePath();
+        String fileContents = HttpUtils.getFileContent(filename);
+        byte buf[] = fileContents.getBytes();
+        switch (requestType) {
+            case "InputStream":
+                InputStream inputStream = new FileInputStream(smallFile.toFile());
+                builder = client.request(uri)
+                                .body(fromInputStream(inputStream));
+                break;
+            case "byteArray":
+                builder = client.request(uri)
+                                .body(fromByteArray(buf));
+                break;
+            case "byteArrays":
+                Iterable iterable = Arrays.asList(buf);
+                builder = client.request(uri)
+                                .body(fromByteArrays(iterable.iterator()));
+                break;
+            case "string":
+                builder = client.request(uri)
+                                .body(fromString(fileContents));
+                break;
+            case "byteArray_offset":
+                builder = client.request(uri)
+                                .body(fromByteArray(buf,
+                                                    DEFAULT_OFFSET,
+                                                    DEFAULT_LENGTH));
+                break;
+            case "file":
+                builder = client.request(uri)
+                                .body(fromFile(smallFile));
+                break;
+            case "string_charset":
+                builder = client.request(uri)
+                                .body(fromString(new String(buf),
+                                                 Charset.defaultCharset()));
+                break;
+            default:
+                builder = null;
+                break;
+        }
+        return builder;
+    }
+
+    public static void checkResponse(final HttpResponse response,
+                                     String requestType,
+                                     final String responseType)
+        throws IOException
+    {
+        String filename = smallFile.toFile().getAbsolutePath();
+        String fileContents = HttpUtils.getFileContent(filename);
+        if (requestType.equals("byteArray_offset")) {
+            fileContents = fileContents.substring(DEFAULT_OFFSET,
+                                                  DEFAULT_OFFSET + DEFAULT_LENGTH);
+        }
+        byte buf[] = fileContents.getBytes();
+        String responseBody;
+        switch (responseType) {
+            case "string":
+                responseBody = response.body(asString());
+                if (!responseBody.equals(fileContents)) {
+                    throw new RuntimeException();
+                }
+                break;
+            case "byteArray":
+                byte arr[] = response.body(asByteArray());
+                if (!Arrays.equals(arr, buf)) {
+                    throw new RuntimeException();
+                }
+                break;
+            case "file":
+                response.body(asFile(Paths.get("barf.txt")));
+                Path downloaded = Paths.get("barf.txt");
+                if (Files.size(downloaded) != fileContents.length()) {
+                    throw new RuntimeException("Size mismatch");
+                }
+                break;
+            case "InputStream":
+                InputStream is = response.body(asInputStream());
+                byte arr1[] = new byte[1024];
+                int byteRead;
+                StringBuilder sb = new StringBuilder();
+                while ((byteRead = is.read(arr1)) != -1) {
+                    sb.append(new String(arr1, 0, byteRead));
+                }
+                if (!sb.toString().equals(fileContents)) {
+                    throw new RuntimeException();
+                }
+                break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/ImmutableHeaders.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,116 @@
+/*
+ * 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
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @run main/othervm ImmutableHeaders
+ * @summary ImmutableHeaders
+ */
+
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.Headers;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.http.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.List;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+public class ImmutableHeaders {
+
+    final static String RESPONSE = "Hello world";
+
+    public static void main(String[] args) throws Exception {
+        HttpServer server = HttpServer.create(new InetSocketAddress(0), 10);
+        ExecutorService e = Executors.newCachedThreadPool();
+        Handler h = new Handler();
+        HttpContext serverContext = server.createContext("/test", h);
+        int port = server.getAddress().getPort();
+        System.out.println("Server port = " + port);
+
+        server.setExecutor(e);
+        server.start();
+        HttpClient client = HttpClient.create()
+                                      .build();
+
+        try {
+            URI uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/test/foo");
+            HttpRequest req = client.request(uri)
+                .headers("X-Foo", "bar")
+                .headers("X-Bar", "foo")
+                .GET();
+
+            try {
+                HttpHeaders hd = req.headers();
+                List<String> v = hd.allValues("X-Foo");
+                if (!v.get(0).equals("bar"))
+                    throw new RuntimeException("Test failed");
+                v.add("XX");
+                throw new RuntimeException("Test failed");
+            } catch (UnsupportedOperationException ex) {
+            }
+            HttpResponse resp = req.response();
+            try {
+                HttpHeaders hd = resp.headers();
+                List<String> v = hd.allValues("X-Foo-Response");
+                if (!v.get(0).equals("resp"))
+                    throw new RuntimeException("Test failed");
+                v.add("XX");
+                throw new RuntimeException("Test failed");
+            } catch (UnsupportedOperationException ex) {
+            }
+
+        } finally {
+            client.executorService().shutdownNow();
+            server.stop(0);
+            e.shutdownNow();
+        }
+        System.out.println("OK");
+    }
+
+   static class Handler implements HttpHandler {
+
+        @Override
+        public void handle(HttpExchange he) throws IOException {
+            String method = he.getRequestMethod();
+            InputStream is = he.getRequestBody();
+            Headers h = he.getResponseHeaders();
+            h.add("X-Foo-Response", "resp");
+            he.sendResponseHeaders(200, RESPONSE.length());
+            OutputStream os = he.getResponseBody();
+            os.write(RESPONSE.getBytes(US_ASCII));
+            os.close();
+        }
+
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/LightWeightHttpServer.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,313 @@
+/*
+ * 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.
+ */
+
+/**
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ */
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsServer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.net.ssl.SSLContext;
+import jdk.testlibrary.SimpleSSLContext;
+
+public class LightWeightHttpServer {
+
+    static SSLContext ctx;
+    static HttpServer httpServer;
+    static HttpsServer httpsServer;
+    static ExecutorService executor;
+    static int port;
+    static int httpsport;
+    static String httproot;
+    static String httpsroot;
+    static ProxyServer proxy;
+    static int proxyPort;
+    static RedirectErrorHandler redirectErrorHandler, redirectErrorHandlerSecure;
+    static RedirectHandler redirectHandler, redirectHandlerSecure;
+    static DelayHandler delayHandler;
+    static final String midSizedFilename = "/files/notsobigfile.txt";
+    static final String smallFilename = "/files/smallfile.txt";
+    static Path midSizedFile;
+    static Path smallFile;
+    static String fileroot;
+
+    public static void initServer() throws IOException {
+
+        Logger logger = Logger.getLogger("com.sun.net.httpserver");
+        ConsoleHandler ch = new ConsoleHandler();
+        logger.setLevel(Level.ALL);
+        ch.setLevel(Level.ALL);
+        logger.addHandler(ch);
+
+        String root = System.getProperty("test.src") + "/docs";
+        InetSocketAddress addr = new InetSocketAddress(0);
+        httpServer = HttpServer.create(addr, 0);
+        if (httpServer instanceof HttpsServer) {
+            throw new RuntimeException("should not be httpsserver");
+        }
+        httpsServer = HttpsServer.create(addr, 0);
+        HttpHandler h = new FileServerHandler(root);
+
+        HttpContext c1 = httpServer.createContext("/files", h);
+        HttpContext c2 = httpsServer.createContext("/files", h);
+        HttpContext c3 = httpServer.createContext("/echo", new EchoHandler());
+        redirectHandler = new RedirectHandler("/redirect");
+        redirectHandlerSecure = new RedirectHandler("/redirect");
+        HttpContext c4 = httpServer.createContext("/redirect", redirectHandler);
+        HttpContext c41 = httpsServer.createContext("/redirect", redirectHandlerSecure);
+        HttpContext c5 = httpsServer.createContext("/echo", new EchoHandler());
+        HttpContext c6 = httpServer.createContext("/keepalive", new KeepAliveHandler());
+        redirectErrorHandler = new RedirectErrorHandler("/redirecterror");
+        redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror");
+        HttpContext c7 = httpServer.createContext("/redirecterror", redirectErrorHandler);
+        HttpContext c71 = httpsServer.createContext("/redirecterror", redirectErrorHandlerSecure);
+        delayHandler = new DelayHandler();
+        HttpContext c8 = httpServer.createContext("/delay", delayHandler);
+        HttpContext c81 = httpsServer.createContext("/delay", delayHandler);
+
+        executor = Executors.newCachedThreadPool();
+        httpServer.setExecutor(executor);
+        httpsServer.setExecutor(executor);
+        ctx = new SimpleSSLContext().get();
+        httpsServer.setHttpsConfigurator(new HttpsConfigurator(ctx));
+        httpServer.start();
+        httpsServer.start();
+
+        port = httpServer.getAddress().getPort();
+        System.out.println("HTTP server port = " + port);
+        httpsport = httpsServer.getAddress().getPort();
+        System.out.println("HTTPS server port = " + httpsport);
+        httproot = "http://127.0.0.1:" + port + "/";
+        httpsroot = "https://127.0.0.1:" + httpsport + "/";
+
+        proxy = new ProxyServer(0, false);
+        proxyPort = proxy.getPort();
+        System.out.println("Proxy port = " + proxyPort);
+    }
+
+    public static void stop() throws IOException {
+        if (httpServer != null) {
+            httpServer.stop(0);
+        }
+        if (httpsServer != null) {
+            httpsServer.stop(0);
+        }
+        if (proxy != null) {
+            proxy.close();
+        }
+        if (executor != null) {
+            executor.shutdownNow();
+        }
+    }
+
+    static class RedirectErrorHandler implements HttpHandler {
+
+        String root;
+        volatile int count = 1;
+
+        RedirectErrorHandler(String root) {
+            this.root = root;
+        }
+
+        synchronized int count() {
+            return count;
+        }
+
+        synchronized void increment() {
+            count++;
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange t)
+                throws IOException {
+            byte[] buf = new byte[2048];
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read(buf) != -1) ;
+            }
+
+            Headers map = t.getResponseHeaders();
+            String redirect = root + "/foo/" + Integer.toString(count);
+            increment();
+            map.add("Location", redirect);
+            t.sendResponseHeaders(301, -1);
+            t.close();
+        }
+    }
+
+    static class RedirectHandler implements HttpHandler {
+
+        String root;
+        volatile int count = 0;
+
+        RedirectHandler(String root) {
+            this.root = root;
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange t)
+                throws IOException {
+            byte[] buf = new byte[2048];
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read(buf) != -1) ;
+            }
+
+            Headers map = t.getResponseHeaders();
+
+            if (count++ < 1) {
+                map.add("Location", root + "/foo/" + count);
+            } else {
+                map.add("Location", SmokeTest.midSizedFilename);
+            }
+            t.sendResponseHeaders(301, -1);
+            t.close();
+        }
+
+        int count() {
+            return count;
+        }
+
+        void reset() {
+            count = 0;
+        }
+    }
+
+    static class KeepAliveHandler implements HttpHandler {
+
+        volatile int counter = 0;
+        HashSet<Integer> portSet = new HashSet<>();
+        volatile int[] ports = new int[4];
+
+        void sleep(int n) {
+            try {
+                Thread.sleep(n);
+            } catch (InterruptedException e) {
+            }
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange t)
+                throws IOException {
+            int remotePort = t.getRemoteAddress().getPort();
+            String result = "OK";
+
+            int n = counter++;
+            /// First test
+            if (n < 4) {
+                ports[n] = remotePort;
+            }
+            if (n == 3) {
+                // check all values in ports[] are the same
+                if (ports[0] != ports[1] || ports[2] != ports[3]
+                        || ports[0] != ports[2]) {
+                    result = "Error " + Integer.toString(n);
+                    System.out.println(result);
+                }
+            }
+            // Second test
+            if (n >= 4 && n < 8) {
+                // delay to ensure ports are different
+                sleep(500);
+                ports[n - 4] = remotePort;
+            }
+            if (n == 7) {
+                // should be all different
+                if (ports[0] == ports[1] || ports[2] == ports[3]
+                        || ports[0] == ports[2]) {
+                    result = "Error " + Integer.toString(n);
+                    System.out.println(result);
+                    System.out.printf("Ports: %d, %d, %d, %d\n",
+                                      ports[0], ports[1], ports[2], ports[3]);
+                }
+                // setup for third test
+                for (int i = 0; i < 4; i++) {
+                    portSet.add(ports[i]);
+                }
+            }
+            // Third test
+            if (n > 7) {
+                // just check that port is one of the ones in portSet
+                if (!portSet.contains(remotePort)) {
+                    System.out.println("UNEXPECTED REMOTE PORT " + remotePort);
+                    result = "Error " + Integer.toString(n);
+                    System.out.println(result);
+                }
+            }
+            byte[] buf = new byte[2048];
+
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read(buf) != -1) ;
+            }
+            t.sendResponseHeaders(200, result.length());
+            OutputStream o = t.getResponseBody();
+            o.write(result.getBytes("US-ASCII"));
+            t.close();
+        }
+    }
+
+    static class DelayHandler implements HttpHandler {
+
+        CyclicBarrier bar1 = new CyclicBarrier(2);
+        CyclicBarrier bar2 = new CyclicBarrier(2);
+        CyclicBarrier bar3 = new CyclicBarrier(2);
+
+        CyclicBarrier barrier1() {
+            return bar1;
+        }
+
+        CyclicBarrier barrier2() {
+            return bar2;
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange he) throws IOException {
+            byte[] buf = Util.readAll(he.getRequestBody());
+            try {
+                bar1.await();
+                bar2.await();
+            } catch (InterruptedException | BrokenBarrierException e) {
+            }
+            he.sendResponseHeaders(200, -1); // will probably fail
+            he.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/ManyRequests.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,194 @@
+/*
+ * 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 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @run main/othervm ManyRequests
+ * @summary Send a large number of requests asynchronously
+ */
+
+//package javaapplication16;
+
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsServer;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLContext;
+import jdk.testlibrary.SimpleSSLContext;
+
+public class ManyRequests {
+
+    public static void main(String[] args) throws Exception {
+        SSLContext ctx = new SimpleSSLContext().get();
+
+        InetSocketAddress addr = new InetSocketAddress(0);
+        HttpsServer server = HttpsServer.create(addr, 0);
+        server.setHttpsConfigurator(new HttpsConfigurator(ctx));
+
+        HttpClient client = HttpClient.create()
+                                      .sslContext(ctx)
+                                      .build();
+        try {
+            test(server, client);
+            System.out.println("OK");
+        } finally {
+            server.stop(0);
+            client.executorService().shutdownNow();
+        }
+    }
+
+    static final int REQUESTS = 1000;
+
+    static void test(HttpsServer server, HttpClient client) throws Exception {
+        int port = server.getAddress().getPort();
+        URI uri = new URI("https://127.0.0.1:" + port + "/foo/x");
+        server.createContext("/foo", new EchoHandler());
+        server.start();
+
+        RequestLimiter limiter = new RequestLimiter(40);
+        Random rand = new Random();
+        CompletableFuture<Void>[] results = new CompletableFuture[REQUESTS];
+        HashMap<HttpRequest,byte[]> bodies = new HashMap<>();
+
+        for (int i=0; i<REQUESTS; i++) {
+            byte[] buf = new byte[i+1];  // different size bodies
+            rand.nextBytes(buf);
+            HttpRequest r = client.request(uri)
+                                  .body(HttpRequest.fromByteArray(buf))
+                                  .POST();
+            bodies.put(r, buf);
+
+            results[i] =
+                limiter.whenOkToSend()
+                       .thenCompose((v) -> r.responseAsync())
+                       .thenCompose((resp) -> {
+                           limiter.requestComplete();
+                           if (resp.statusCode() != 200) {
+                               resp.bodyAsync(HttpResponse.ignoreBody());
+                               String s = "Expected 200, got: " + resp.statusCode();
+                               return completedWithIOException(s);
+                           }
+                           return resp.bodyAsync(HttpResponse.asByteArray())
+                                      .thenApply((b) -> new Pair<>(resp, b));
+                       })
+                      .thenAccept((pair) -> {
+                          HttpRequest request = pair.t.request();
+                          byte[] requestBody = bodies.get(request);
+                          check(Arrays.equals(requestBody, pair.u),
+                                "bodies not equal");
+
+                      });
+        }
+        // wait for them all to complete and throw exception in case of error
+        CompletableFuture.allOf(results).join();
+    }
+
+    static <T> CompletableFuture<T> completedWithIOException(String message) {
+        CompletableFuture<T> cf = new CompletableFuture<>();
+        cf.completeExceptionally(new IOException(message));
+        return cf;
+    }
+
+    static final class Pair<T,U> {
+        Pair(T t, U u) {
+            this.t = t; this.u = u;
+        }
+        T t;
+        U u;
+    }
+
+    /**
+     * A simple limiter for controlling the number of requests to be run in
+     * parallel whenOkToSend() is called which returns a CF<Void> that allows
+     * each individual request to proceed, or block temporarily (blocking occurs
+     * on the waiters list here. As each request actually completes
+     * requestComplete() is called to notify this object, and allow some
+     * requests to continue.
+     */
+    static class RequestLimiter {
+
+        static final CompletableFuture<Void> COMPLETED_FUTURE =
+                CompletableFuture.completedFuture(null);
+
+        final int maxnumber;
+        final LinkedList<CompletableFuture<Void>> waiters;
+        int number;
+        boolean blocked;
+
+        RequestLimiter(int maximum) {
+            waiters = new LinkedList<>();
+            maxnumber = maximum;
+        }
+
+        synchronized void requestComplete() {
+            number--;
+            // don't unblock until number of requests has halved.
+            if ((blocked && number <= maxnumber / 2) ||
+                        (!blocked && waiters.size() > 0)) {
+                int toRelease = Math.min(maxnumber - number, waiters.size());
+                for (int i=0; i<toRelease; i++) {
+                    CompletableFuture<Void> f = waiters.remove();
+                    number ++;
+                    f.complete(null);
+                }
+                blocked = number >= maxnumber;
+            }
+        }
+
+        synchronized CompletableFuture<Void> whenOkToSend() {
+            if (blocked || number + 1 >= maxnumber) {
+                blocked = true;
+                CompletableFuture<Void> r = new CompletableFuture<>();
+                waiters.add(r);
+                return r;
+            } else {
+                number++;
+                return COMPLETED_FUTURE;
+            }
+        }
+    }
+
+    static void check(boolean cond, Object... msg) {
+        if (cond)
+            return;
+        StringBuilder sb = new StringBuilder();
+        for (Object o : msg)
+            sb.append(o);
+        throw new RuntimeException(sb.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/ProxyServer.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,319 @@
+/*
+ * 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.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+
+/**
+ * A minimal proxy server that supports CONNECT tunneling. It does not do
+ * any header transformations. In future this could be added.
+ * Two threads are created per client connection. So, it's not
+ * intended for large numbers of parallel connections.
+ */
+public class ProxyServer extends Thread implements Closeable {
+
+    ServerSocket listener;
+    int port;
+    volatile boolean debug;
+
+    /**
+     * Create proxy on port (zero means don't care). Call getPort()
+     * to get the assigned port.
+     */
+    public ProxyServer(Integer port) throws IOException {
+        this(port, false);
+    }
+
+    public ProxyServer(Integer port, Boolean debug) throws IOException {
+        this.debug = debug;
+        listener = new ServerSocket(port);
+        this.port = listener.getLocalPort();
+        setName("ProxyListener");
+        setDaemon(true);
+        connections = new LinkedList<>();
+        start();
+    }
+
+    public ProxyServer(String s) {  }
+
+    /**
+     * Returns the port number this proxy is listening on
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Shuts down the proxy, probably aborting any connections
+     * currently open
+     */
+    public void close() throws IOException {
+        if (debug) System.out.println("Proxy: closing");
+            done = true;
+        listener.close();
+        for (Connection c : connections) {
+            if (c.running()) {
+                c.close();
+            }
+        }
+    }
+
+    List<Connection> connections;
+
+    volatile boolean done;
+
+    public void run() {
+        if (System.getSecurityManager() == null) {
+            execute();
+        } else {
+            // so calling domain does not need to have socket permission
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    execute();
+                    return null;
+                }
+            });
+        }
+    }
+
+    public void execute() {
+        try {
+            while(!done) {
+                Socket s = listener.accept();
+                if (debug)
+                    System.out.println("Client: " + s);
+                Connection c = new Connection(s);
+                connections.add(c);
+            }
+        } catch(Throwable e) {
+            if (debug && !done) {
+                System.out.println("Fatal error: Listener: " + e);
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Transparently forward everything, once we know what the destination is
+     */
+    class Connection {
+
+        Socket clientSocket, serverSocket;
+        Thread out, in;
+        volatile InputStream clientIn, serverIn;
+        volatile OutputStream clientOut, serverOut;
+
+        boolean forwarding = false;
+
+        final static int CR = 13;
+        final static int LF = 10;
+
+        Connection(Socket s) throws IOException {
+            this.clientSocket= s;
+            this.clientIn = new BufferedInputStream(s.getInputStream());
+            this.clientOut = s.getOutputStream();
+            init();
+        }
+
+        byte[] readHeaders(InputStream is) throws IOException {
+            byte[] outbuffer = new byte[8000];
+            int crlfcount = 0;
+            int bytecount = 0;
+            int c;
+            while ((c=is.read()) != -1 && bytecount < outbuffer.length) {
+                outbuffer[bytecount++] = (byte)c;
+                if (debug) System.out.write(c);
+                // were looking for CRLFCRLF sequence
+                if (c == CR || c == LF) {
+                    switch(crlfcount) {
+                        case 0:
+                            if (c == CR) crlfcount ++;
+                            break;
+                        case 1:
+                            if (c == LF) crlfcount ++;
+                            break;
+                        case 2:
+                            if (c == CR) crlfcount ++;
+                            break;
+                        case 3:
+                            if (c == LF) crlfcount ++;
+                            break;
+                    }
+                } else {
+                    crlfcount = 0;
+                }
+                if (crlfcount == 4) {
+                    break;
+                }
+            }
+            byte[] ret = new byte[bytecount];
+            System.arraycopy(outbuffer, 0, ret, 0, bytecount);
+            return ret;
+        }
+
+        boolean running() {
+            return out.isAlive() || in.isAlive();
+        }
+
+        public void close() throws IOException {
+            if (debug) System.out.println("Closing connection (proxy)");
+            if (serverSocket != null) serverSocket.close();
+            if (clientSocket != null) clientSocket.close();
+        }
+
+        int findCRLF(byte[] b) {
+            for (int i=0; i<b.length-1; i++) {
+                if (b[i] == CR && b[i+1] == LF) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        public void init() {
+            try {
+                byte[] buf = readHeaders(clientIn);
+                int p = findCRLF(buf);
+                if (p == -1) {
+                    close();
+                    return;
+                }
+                String cmd = new String(buf, 0, p, "US-ASCII");
+                String[] params = cmd.split(" ");
+                if (params[0].equals("CONNECT")) {
+                    doTunnel(params[1]);
+                } else {
+                    doProxy(params[1], buf, p, cmd);
+                }
+            } catch (IOException e) {
+                if (debug) {
+                    System.out.println (e);
+                }
+                try {close(); } catch (IOException e1) {}
+            }
+        }
+
+        void doProxy(String dest, byte[] buf, int p, String cmdLine)
+            throws IOException
+        {
+            try {
+                URI uri = new URI(dest);
+                if (!uri.isAbsolute()) {
+                    throw new IOException("request URI not absolute");
+                }
+                dest = uri.getAuthority();
+                // now extract the path from the URI and recreate the cmd line
+                int sp = cmdLine.indexOf(' ');
+                String method = cmdLine.substring(0, sp);
+                cmdLine = method + " " + uri.getPath() + " HTTP/1.1";
+                int x = cmdLine.length() - 1;
+                int i = p;
+                while (x >=0) {
+                    buf[i--] = (byte)cmdLine.charAt(x--);
+                }
+                i++;
+
+                commonInit(dest, 80);
+                serverOut.write(buf, i, buf.length-i);
+                proxyCommon();
+
+            } catch (URISyntaxException e) {
+                throw new IOException(e);
+            }
+        }
+
+        void commonInit(String dest, int defaultPort) throws IOException {
+            int port;
+            String[] hostport = dest.split(":");
+            if (hostport.length == 1) {
+                port = defaultPort;
+            } else {
+                port = Integer.parseInt(hostport[1]);
+            }
+            if (debug) System.out.printf("Server: (%s/%d)\n", hostport[0], port);
+            serverSocket = new Socket(hostport[0], port);
+            serverOut = serverSocket.getOutputStream();
+
+            serverIn = new BufferedInputStream(serverSocket.getInputStream());
+        }
+
+        void proxyCommon() throws IOException {
+            out = new Thread(() -> {
+                try {
+                    byte[] bb = new byte[8000];
+                    int n;
+                    while ((n = clientIn.read(bb)) != -1) {
+                        serverOut.write(bb, 0, n);
+                    }
+                    serverSocket.close();
+                    clientSocket.close();
+                } catch (IOException e) {
+                    if (debug) {
+                        System.out.println (e);
+                    }
+                }
+            });
+            in = new Thread(() -> {
+                try {
+                    byte[] bb = new byte[8000];
+                    int n;
+                    while ((n = serverIn.read(bb)) != -1) {
+                        clientOut.write(bb, 0, n);
+                    }
+                    serverSocket.close();
+                    clientSocket.close();
+                } catch (IOException e) {
+                    if (debug) {
+                        System.out.println(e);
+                        e.printStackTrace();
+                    }
+                }
+            });
+            out.setName("Proxy-outbound");
+            out.setDaemon(true);
+            in.setDaemon(true);
+            in.setName("Proxy-inbound");
+            out.start();
+            in.start();
+        }
+
+        void doTunnel(String dest) throws IOException {
+            commonInit(dest, 443);
+            clientOut.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());
+            proxyCommon();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        int port = Integer.parseInt(args[0]);
+        boolean debug = args.length > 1 && args[1].equals("-debug");
+        System.out.println("Debugging : " + debug);
+        ProxyServer ps = new ProxyServer(port, debug);
+        System.out.println("Proxy server listening on port " + ps.getPort());
+        while (true) {
+            Thread.sleep(5000);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/QuickResponses.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @test
+ * @bug 8087112
+ * @build Server
+ * @run main/othervm -Djava.net.HttpClient.log=all QuickResponses
+ */
+
+/**
+ * Tests the buffering of data on connections across multiple
+ * responses
+ */
+public class QuickResponses {
+
+    static Server server;
+
+    static String response(String body) {
+        return "HTTP/1.1 200 OK\r\nContent-length: " + Integer.toString(body.length())
+                + "\r\n\r\n" + body;
+    }
+
+    static final String responses[] = {
+        "Lorem ipsum",
+        "dolor sit amet",
+        "consectetur adipiscing elit, sed do eiusmod tempor",
+        "quis nostrud exercitation ullamco",
+        "laboris nisi",
+        "ut",
+        "aliquip ex ea commodo consequat." +
+        "Duis aute irure dolor in reprehenderit in voluptate velit esse" +
+        "cillum dolore eu fugiat nulla pariatur.",
+        "Excepteur sint occaecat cupidatat non proident."
+    };
+
+    static String entireResponse() {
+        String s = "";
+        for (String r : responses) {
+            s += response(r);
+        }
+        return s;
+    }
+
+    public static void main(String[] args) throws Exception {
+        server = new Server(0);
+        URI uri = new URI(server.getURL());
+
+        HttpRequest request = HttpRequest.create(uri)
+                .GET();
+
+        CompletableFuture<HttpResponse> cf1 = request.responseAsync();
+        Server.Connection s1 = server.activity();
+        s1.send(entireResponse());
+
+
+        HttpResponse r = cf1.join();
+        if (r.statusCode()!= 200 || !r.body(HttpResponse.asString()).equals(responses[0]))
+            throw new RuntimeException("Failed on first response");
+
+        //now get the same identical response, synchronously to ensure same connection
+        int remaining = responses.length - 1;
+
+        for (int i=0; i<remaining; i++) {
+            r = HttpRequest.create(uri)
+                    .GET()
+                    .response();
+            if (r.statusCode()!= 200)
+                throw new RuntimeException("Failed");
+
+            String body = r.body(HttpResponse.asString());
+            if (!body.equals(responses[i+1]))
+                throw new RuntimeException("Failed");
+        }
+        HttpClient.getDefault().executorService().shutdownNow();
+        System.out.println("OK");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/RequestBodyTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,169 @@
+/*
+ * 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 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @run main/othervm RequestBodyTest
+ */
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.Executors;
+import javax.net.ssl.SSLContext;
+
+public class RequestBodyTest {
+
+    final static String STRING = "string";
+    final static String BYTE_ARRAY = "byteArray";
+    final static String BYTE_ARRAYS = "byteArrays";
+    final static String BYTE_ARRAY_OFFSET = "byteArray_offset";
+    final static String FILE = "file";
+    final static String STRING_CHARSET = "string_charset";
+    final static String INPUTSTREAM = "InputStream";
+
+    final static String midSizedFilename = "/files/notsobigfile.txt";
+    final static String smallFilename = "/files/smallfile.txt";
+    static Path midSizedFile;
+    static Path smallFile;
+    static String fileroot;
+    static HttpClient client;
+    static SSLContext ctx;
+    static String httproot;
+    static String httpsroot;
+
+    public static void main(String args[]) throws Exception {
+        fileroot = System.getProperty("test.src") + "/docs";
+        midSizedFile = Paths.get(fileroot + midSizedFilename);
+        smallFile = Paths.get(fileroot + smallFilename);
+        //start the server
+        LightWeightHttpServer.initServer();
+
+        httproot = LightWeightHttpServer.httproot;
+        httpsroot = LightWeightHttpServer.httpsroot;
+        ctx = LightWeightHttpServer.ctx;
+        client = HttpClient.create().sslContext(ctx)
+                .followRedirects(HttpClient.Redirect.ALWAYS)
+                .executorService(Executors.newCachedThreadPool())
+                .build();
+
+        String TARGET = httproot + "echo/foo";
+        boolean isSync = false;
+        requestBodyTypes(TARGET, STRING, STRING, isSync);
+        requestBodyTypes(TARGET, STRING, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, STRING, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, STRING, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, STRING, FILE, isSync);
+
+        requestBodyTypes(TARGET, BYTE_ARRAY, STRING, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, FILE, isSync);
+
+        requestBodyTypes(TARGET, BYTE_ARRAYS, STRING, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, FILE, isSync);
+
+        requestBodyTypes(TARGET, INPUTSTREAM, STRING, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, FILE, isSync);
+
+        requestBodyTypes(TARGET, FILE, STRING, isSync);
+        requestBodyTypes(TARGET, FILE, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, FILE, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, FILE, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, FILE, FILE, isSync);
+
+        isSync = true;
+        requestBodyTypes(TARGET, STRING, STRING, isSync);
+        requestBodyTypes(TARGET, STRING, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, STRING, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, STRING, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, STRING, FILE, isSync);
+
+        requestBodyTypes(TARGET, BYTE_ARRAY, STRING, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, FILE, isSync);
+
+        requestBodyTypes(TARGET, BYTE_ARRAYS, STRING, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, FILE, isSync);
+
+        requestBodyTypes(TARGET, INPUTSTREAM, STRING, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, FILE, isSync);
+
+        requestBodyTypes(TARGET, FILE, STRING, isSync);
+        requestBodyTypes(TARGET, FILE, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, FILE, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, FILE, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, FILE, FILE, isSync);
+
+    }
+
+    static void requestBodyTypes(final String target,
+                                 final String requestType,
+                                 final String responseType,
+                                 final boolean isAsync)
+        throws Exception
+    {
+        System.out.println("Running test_request_body_type " + requestType +
+                " and response type " + responseType + " and sync=" + isAsync);
+        URI uri = new URI(target);
+        byte buf[];
+        String filename = smallFile.toFile().getAbsolutePath();
+        String fileContents = HttpUtils.getFileContent(filename);
+        buf = fileContents.getBytes();
+        HttpRequest.Builder builder = HttpUtils.getHttpRequestBuilder(client,
+                                                                      requestType,
+                                                                      uri);
+        HttpResponse response;
+        if (!isAsync) {
+            response = builder.GET().response();
+        } else {
+            response = builder.GET().responseAsync().join();
+        }
+        HttpUtils.checkResponse(response, requestType, responseType);
+        System.out.println("OK");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/Server.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ */
+
+//package javaapplication16;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A cut-down Http/1 Server for testing various error situations
+ *
+ * use interrupt() to halt
+ */
+public class Server extends Thread {
+
+    ServerSocket ss;
+    List<Connection> sockets;
+    AtomicInteger counter = new AtomicInteger(0);
+
+    // waits up to 20 seconds for something to happen
+    // dont use this unless certain activity coming.
+    public Connection activity() {
+        for (int i = 0; i < 80 * 100; i++) {
+            for (Connection c : sockets) {
+                if (c.poll()) {
+                    return c;
+                }
+            }
+            try {
+                Thread.sleep(250);
+            } catch (InterruptedException e) {
+            }
+        }
+        return null;
+    }
+
+    // clears all current connections on Server.
+    public void reset() {
+        for (Connection c : sockets) {
+            c.close();
+        }
+    }
+
+    /**
+     * Reads data into an ArrayBlockingQueue<String> where each String
+     * is a line of input, that was terminated by CRLF (not included)
+     */
+    class Connection extends Thread {
+        Connection(Socket s) throws IOException {
+            this.socket = s;
+            id = counter.incrementAndGet();
+            is = s.getInputStream();
+            os = s.getOutputStream();
+            incoming = new ArrayBlockingQueue<>(100);
+            setName("Server-Connection");
+            setDaemon(true);
+            start();
+        }
+        final Socket socket;
+        final int id;
+        final InputStream is;
+        final OutputStream os;
+        final ArrayBlockingQueue<String> incoming;
+
+        final static String CRLF = "\r\n";
+
+        // sentinel indicating connection closed
+        final static String CLOSED = "C.L.O.S.E.D";
+        volatile boolean closed = false;
+
+        @Override
+        public void run() {
+            byte[] buf = new byte[256];
+            String s = "";
+            try {
+                while (true) {
+                    int n = is.read(buf);
+                    if (n == -1) {
+                        cleanup();
+                        return;
+                    }
+                    String s0 = new String(buf, 0, n, StandardCharsets.ISO_8859_1);
+                    s = s + s0;
+                    int i;
+                    while ((i=s.indexOf(CRLF)) != -1) {
+                        String s1 = s.substring(0, i+2);
+                        incoming.put(s1);
+                        if (i+2 == s.length()) {
+                            s = "";
+                            break;
+                        }
+                        s = s.substring(i+2);
+                    }
+                }
+            } catch (IOException |InterruptedException e1) {
+                cleanup();
+            } catch (Throwable t) {
+                System.out.println("X: " + t);
+                cleanup();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "Server.Connection: " + socket.toString();
+        }
+
+        public void sendHttpResponse(int code, String body, String... headers)
+            throws IOException
+        {
+            String r1 = "HTTP/1.1 " + Integer.toString(code) + " status" + CRLF;
+            for (int i=0; i<headers.length; i+=2) {
+                r1 += headers[i] + ": " + headers[i+1] + CRLF;
+            }
+            int clen = body == null ? 0 : body.length();
+            r1 += "Content-Length: " + Integer.toString(clen) + CRLF;
+            r1 += CRLF;
+            if (body != null) {
+                r1 += body;
+            }
+            send(r1);
+        }
+
+        // content-length is 10 bytes too many
+        public void sendIncompleteHttpResponseBody(int code) throws IOException {
+            String body = "Hello World Helloworld Goodbye World";
+            String r1 = "HTTP/1.1 " + Integer.toString(code) + " status" + CRLF;
+            int clen = body.length() + 10;
+            r1 += "Content-Length: " + Integer.toString(clen) + CRLF;
+            r1 += CRLF;
+            if (body != null) {
+                r1 += body;
+            }
+            send(r1);
+        }
+
+        public void sendIncompleteHttpResponseHeaders(int code)
+            throws IOException
+        {
+            String r1 = "HTTP/1.1 " + Integer.toString(code) + " status" + CRLF;
+            send(r1);
+        }
+
+        public void send(String r) throws IOException {
+            os.write(r.getBytes(StandardCharsets.ISO_8859_1));
+        }
+
+        public synchronized void close() {
+            cleanup();
+            closed = true;
+            incoming.clear();
+        }
+
+        public String nextInput(long timeout, TimeUnit unit) {
+            String result = "";
+            while (poll()) {
+                try {
+                    String s = incoming.poll(timeout, unit);
+                    if (s == null && closed) {
+                        return CLOSED;
+                    } else {
+                        result += s;
+                    }
+                } catch (InterruptedException e) {
+                    return null;
+                }
+            }
+            return result;
+        }
+
+        public String nextInput() {
+            return nextInput(0, TimeUnit.SECONDS);
+        }
+
+        public boolean poll() {
+            return incoming.peek() != null;
+        }
+
+        private void cleanup() {
+            try {
+                socket.close();
+            } catch (IOException e) {}
+            sockets.remove(this);
+        }
+    }
+
+    Server(int port) throws IOException {
+        ss = new ServerSocket(port);
+        sockets = Collections.synchronizedList(new LinkedList<>());
+        setName("Test-Server");
+        setDaemon(true);
+        start();
+    }
+
+    Server() throws IOException {
+        this(0);
+    }
+
+    int port() {
+        return ss.getLocalPort();
+    }
+
+    public String getURL() {
+        return "http://127.0.0.1:" + port() + "/foo/";
+    }
+
+    public void close() {
+        try {
+            ss.close();
+        } catch (IOException e) {
+        }
+        for (Connection c : sockets) {
+            c.close();
+        }
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            try {
+                Socket s = ss.accept();
+                Connection c = new Connection(s);
+                sockets.add(c);
+            } catch (IOException e) {
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/SmokeTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,949 @@
+/*
+ * 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 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @run main/othervm SmokeTest
+ */
+
+//package javaapplication16;
+
+import com.sun.net.httpserver.*;
+import java.net.*;
+import java.net.http.*;
+import java.io.*;
+import java.util.concurrent.*;
+import javax.net.ssl.*;
+import java.nio.file.*;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import jdk.testlibrary.SimpleSSLContext;
+import static java.net.http.HttpRequest.*;
+import static java.net.http.HttpResponse.*;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * * Basic smoke test for Http/1.1 client
+ * - basic request response
+ * - request body POST
+ * - response body GET
+ * - redirect
+ * - chunked request/response
+ * - SSL
+ * - proxies
+ * - 100 continue
+ * - check keep alive appears to be working
+ * - cancel of long request
+ *
+ * Uses a FileServerHandler serving a couple of known files
+ * in docs directory.
+ */
+public class SmokeTest {
+    static SSLContext ctx;
+    static HttpServer s1 ;
+    static HttpsServer s2;
+    static ExecutorService executor;
+    static int port;
+    static int httpsport;
+    static String httproot;
+    static String httpsroot;
+    static HttpClient client;
+    static ProxyServer proxy;
+    static int proxyPort;
+    static RedirectErrorHandler redirectErrorHandler, redirectErrorHandlerSecure;
+    static RedirectHandler redirectHandler, redirectHandlerSecure;
+    static DelayHandler delayHandler;
+    final static String midSizedFilename = "/files/notsobigfile.txt";
+    final static String smallFilename = "/files/smallfile.txt";
+    static Path midSizedFile;
+    static Path smallFile;
+    static String fileroot;
+
+    static String getFileContent(String path) throws IOException {
+        FileInputStream fis = new FileInputStream(path);
+        byte[] buf = new byte[2000];
+        StringBuilder sb = new StringBuilder();
+        int n;
+        while ((n=fis.read(buf)) != -1) {
+            sb.append(new String(buf, 0, n, "US-ASCII"));
+        }
+        return sb.toString();
+    }
+
+    public static void main(String[] args) throws Exception {
+        initServer();
+        fileroot = System.getProperty ("test.src", ".")+ "/docs";
+        midSizedFile = Paths.get(fileroot + midSizedFilename);
+        smallFile = Paths.get(fileroot + smallFilename);
+
+        client = HttpClient.create()
+                           .sslContext(ctx)
+                           .followRedirects(HttpClient.Redirect.ALWAYS)
+                           .executorService(Executors.newCachedThreadPool())
+                           .build();
+
+        try {
+            test1(httproot + "files/foo.txt", true);
+
+            test1(httproot + "files/foo.txt", false);
+            test1(httpsroot + "files/foo.txt", true);
+            test1(httpsroot + "files/foo.txt", false);
+            test2(httproot + "echo/foo", "This is a short test");
+            test2(httpsroot + "echo/foo", "This is a short test");
+
+            test3(httproot + "redirect/foo.txt");
+            test3(httpsroot + "redirect/foo.txt");
+            test4(httproot + "files/foo.txt");
+            test4(httpsroot + "files/foo.txt");
+            test5(httproot + "echo/foo", true);
+            test5(httpsroot + "echo/foo", true);
+            test5(httproot + "echo/foo", false);
+            test5(httpsroot + "echo/foo", false);
+
+            test6(httproot + "echo/foo", true);
+            test6(httpsroot + "echo/foo", true);
+            test6(httproot + "echo/foo", false);
+            test6(httpsroot + "echo/foo", false);
+
+            test7(httproot + "keepalive/foo");
+
+            test8(httproot + "files/foo.txt", true);
+            test8(httproot + "files/foo.txt", false);
+            test8(httpsroot + "files/foo.txt", true);
+            test8(httpsroot + "files/foo.txt", false);
+            // disabled test9();
+
+            test10(httproot + "redirecterror/foo.txt");
+
+            test10(httpsroot + "redirecterror/foo.txt");
+
+            test11(httproot + "echo/foo");
+            test11(httpsroot + "echo/foo");
+            //test12(httproot + "delay/foo", delayHandler);
+
+        } finally {
+            s1.stop(0);
+            s2.stop(0);
+            proxy.close();
+            executor.shutdownNow();
+            client.executorService().shutdownNow();
+        }
+    }
+
+    static class Auth extends java.net.Authenticator {
+        volatile int count = 0;
+        @Override
+        protected PasswordAuthentication getPasswordAuthentication() {
+            if (count++ == 0) {
+                return new PasswordAuthentication("user", "passwd".toCharArray());
+            } else {
+                return new PasswordAuthentication("user", "goober".toCharArray());
+            }
+        }
+        int count() {
+            return count;
+        }
+    }
+
+    // Basic test
+    static void test1(String target, boolean fixedLen) throws Exception {
+        System.out.print("test1: " + target);
+        URI uri = new URI(target);
+
+        HttpRequest.Builder builder = client.request(uri)
+                                             .body(noBody());
+
+        if (fixedLen) {
+            builder.header("XFixed", "yes");
+        }
+
+        HttpResponse response = builder.GET().response();
+
+        String body = response.body(asString());
+        if (!body.equals("This is foo.txt\r\n")) {
+            throw new RuntimeException();
+        }
+
+        // repeat async
+        response = builder.GET().responseAsync().join();
+
+        body = response.body(asString());
+        if (!body.equals("This is foo.txt\r\n")) {
+            throw new RuntimeException();
+        }
+        System.out.println(" OK");
+    }
+
+    // POST use echo to check reply
+    static void test2(String s, String body) throws Exception {
+        System.out.print("test2: " + s);
+        URI uri = new URI(s);
+
+        HttpResponse response = client.request(uri)
+                                       .body(fromString(body))
+                                       .POST()
+                                       .response();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException(
+                "Expected 200, got [ " + response.statusCode() + " ]");
+        }
+        String reply = response.body(asString());
+        if (!reply.equals(body)) {
+            throw new RuntimeException(
+                "Body mismatch: expected [" + body + "], got [" + reply + "]");
+        }
+        System.out.println(" OK");
+    }
+
+    // Redirect
+    static void test3(String s) throws Exception {
+        System.out.print("test3: " + s);
+        URI uri = new URI(s);
+        RedirectHandler handler = uri.getScheme().equals("https")
+                ? redirectHandlerSecure : redirectHandler;
+
+        HttpResponse response = client.request(uri)
+                                      .body(noBody())
+                                      .GET()
+                                      .response();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException(
+                "Expected 200, got [ " + response.statusCode() + " ]");
+        } else {
+            response.body(HttpResponse.asFile(Paths.get("redir1.txt")));
+        }
+
+        Path downloaded = Paths.get("redir1.txt");
+        if (Files.size(downloaded) != Files.size(midSizedFile)) {
+            throw new RuntimeException("Size mismatch");
+        }
+
+        System.out.printf(" (count: %d) ", handler.count());
+        // repeat with async api
+
+        handler.reset();
+
+        response = client.request(uri)
+                         .body(noBody())
+                         .GET()
+                         .responseAsync()
+                         .join();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException(
+                    "Expected 200, got [ " + response.statusCode() + " ]");
+        } else {
+            response.body(HttpResponse.asFile(Paths.get("redir2.txt")));
+        }
+
+        downloaded = Paths.get("redir2.txt");
+        if (Files.size(downloaded) != Files.size(midSizedFile)) {
+            throw new RuntimeException("Size mismatch 2");
+        }
+        System.out.printf(" (count: %d) ", handler.count());
+        System.out.println(" OK");
+    }
+
+    // Proxies
+    static void test4(String s) throws Exception {
+        System.out.print("test4: " + s);
+        URI uri = new URI(s);
+        InetSocketAddress proxyAddr = new InetSocketAddress("127.0.0.1", proxyPort);
+        String filename = fileroot + uri.getPath();
+
+        HttpClient cl = HttpClient.create()
+                                  .proxy(ProxySelector.of(proxyAddr))
+                                  .sslContext(ctx)
+                                  .build();
+
+        CompletableFuture<String> fut = cl.request(uri)
+                                          .body(noBody())
+                                          .GET()
+                                          .responseAsync()
+                                          .thenCompose((HttpResponse response) ->
+                                                          response.bodyAsync(asString())
+                                          );
+
+        String body = fut.get(5, TimeUnit.HOURS);
+
+        String fc = getFileContent(filename);
+
+        if (!body.equals(fc)) {
+            throw new RuntimeException(
+                    "Body mismatch: expected [" + body + "], got [" + fc + "]");
+        }
+        cl.executorService().shutdownNow();
+        System.out.println(" OK");
+    }
+
+    // 100 Continue: use echo target
+    static void test5(String target, boolean fixedLen) throws Exception {
+        System.out.print("test5: " + target);
+        URI uri = new URI(target);
+        String requestBody = generateString(12 * 1024 + 13);
+
+        HttpRequest.Builder builder = client.request(uri)
+                                            .expectContinue(true)
+                                            .body(fromString(requestBody));
+
+        if (fixedLen) {
+            builder.header("XFixed", "yes");
+        }
+
+        HttpResponse response = builder.GET().response();
+
+        String body = response.body(asString());
+
+        if (!body.equals(requestBody)) {
+            throw new RuntimeException(
+                    "Body mismatch: expected [" + body + "], got [" + body + "]");
+        }
+        System.out.println(" OK");
+    }
+
+    // use echo
+    static void test6(String target, boolean fixedLen) throws Exception {
+        System.out.print("test6: " + target);
+        URI uri = new URI(target);
+        String requestBody = generateString(12 * 1024 + 3);
+
+        HttpRequest.Builder builder = client.request(uri)
+                                            .body(noBody());
+
+        if (fixedLen) {
+            builder.header("XFixed", "yes");
+        }
+
+        HttpResponse response = builder.GET().response();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException(
+                    "Expected 200, got [ " + response.statusCode() + " ]");
+        }
+
+        String responseBody = response.body(asString());
+
+        if (responseBody.equals(requestBody)) {
+            throw new RuntimeException(
+                    "Body mismatch: expected [" + requestBody + "], got [" + responseBody + "]");
+        }
+        System.out.println(" OK");
+    }
+
+    @SuppressWarnings("rawtypes")
+    static void test7(String target) throws Exception {
+        System.out.print("test7: " + target);
+
+        // First test
+        URI uri = new URI(target);
+        for (int i=0; i<4; i++) {
+            HttpResponse r = client.request(uri)
+                                   .body(noBody())
+                                   .GET()
+                                   .response();
+            String body = r.body(asString());
+            if (!body.equals("OK")) {
+                throw new RuntimeException("Expected OK, got: " + body);
+            }
+        }
+
+        // Second test: 4 x parallel
+        List<CompletableFuture<HttpResponse>> futures = new LinkedList<>();
+        for (int i=0; i<4; i++) {
+            futures.add(client.request(uri)
+                              .body(noBody())
+                              .GET()
+                              .responseAsync());
+        }
+        // all sent?
+        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+                         .join();
+
+        List<CompletableFuture<String>> futureBodies = new LinkedList<>();
+        for (int i=0; i<4; i++) {
+            futureBodies.add(futures.get(i)
+                                    .join()
+                                    .bodyAsync(asString()));
+        }
+        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+                         .join();
+
+        for (CompletableFuture<String> future : futureBodies) {
+            String body = future.get();
+            if (!body.equals("OK")) {
+                throw new RuntimeException("Expected OK, got: " + body);
+            }
+        }
+
+        // Third test: Multiple of 4 parallel requests
+        BlockingQueue<String> q = new LinkedBlockingQueue<>();
+        for (int i=0; i<4; i++) {
+            client.request(uri)
+                  .body(noBody())
+                  .GET()
+                  .responseAsync()
+                  .thenApply((HttpResponse resp) -> {
+                      String body = resp.body(asString());
+                      putQ(q, body);
+                      return body;
+                  });
+        }
+        // we've sent four requests. Now, just send another request
+        // as each response is received. The idea is to ensure that
+        // only four sockets ever get used.
+
+        for (int i=0; i<100; i++) {
+            // block until response received
+            String body = takeQ(q);
+            if (!body.equals("OK")) {
+                throw new RuntimeException(body);
+            }
+            client.request(uri)
+                  .body(noBody())
+                  .GET()
+                  .responseAsync()
+                  .thenApply((HttpResponse resp) -> {
+                      String body1 = resp.body(asString());
+                      putQ(q, body1);
+                      return body1;
+                  });
+        }
+        // should be four left
+        for (int i=0; i<4; i++) {
+            takeQ(q);
+        }
+        System.out.println(" OK");
+    }
+
+    static String takeQ(BlockingQueue<String> q) {
+        String r = null;
+        try {
+            r = q.take();
+        } catch (InterruptedException e) {}
+
+        return r;
+    }
+
+    static void putQ(BlockingQueue<String> q, String o) {
+        try {
+            q.put(o);
+        } catch (InterruptedException e) {
+            // can't happen
+        }
+    }
+
+    static void test8(String target, boolean fixedLen) throws Exception {
+        System.out.print("test8: " + target);
+        URI uri = new URI(target);
+
+        HttpRequest.Builder builder = client.request(uri)
+                                            .body(noBody());
+
+        if (fixedLen) {
+            builder.header("XFixed", "yes");
+        }
+
+        HttpResponse response = builder.GET().response();
+
+        StringBuilder sb = new StringBuilder();
+
+        InputStream is = response.body(asInputStream());
+        int c;
+        byte[] buf = new byte[2048];
+        while ((c = is.read(buf)) != -1) {
+            for (int i=0; i<c; i++)
+                sb.append((char)buf[i]);
+        }
+        is.close();
+        String body = sb.toString();
+
+        if (!body.equals("This is foo.txt\r\n")) {
+            throw new RuntimeException("Expected \"This is foo.txt\", got: " + body);
+        }
+        System.out.println(" OK");
+    }
+
+    // Chunked output stream
+    static void test11(String target) throws Exception {
+        System.out.print("test11: " + target);
+        URI uri = new URI(target);
+
+        FileInputStream file = new FileInputStream(smallFile.toFile());
+
+        HttpRequest.Builder builder = client.request(uri)
+                                            .body(HttpRequest.fromInputStream(file));
+        HttpResponse response = builder.POST().response();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException("Wrong response code");
+        }
+
+        Path download = Paths.get("test11.txt");
+        download.toFile().delete();
+        response.body(HttpResponse.asFile(download));
+
+        if (Files.size(download) != Files.size(smallFile)) {
+            System.out.println("Original size: " + Files.size(smallFile));
+            System.out.println("Downloaded size: " + Files.size(download));
+            throw new RuntimeException("Size mismatch");
+        }
+        System.out.println(" OK");
+    }
+
+    // cancel
+    /*
+    static void test12(String target, DelayHandler h) throws Exception {
+        System.out.print("test12: " + target);
+        URI uri = new URI(target);
+
+        HttpRequest.Builder builder = client
+            .request(uri)
+            .body(HttpRequest.fromString("Hello world"));
+
+        HttpRequest request = builder
+                .GET();
+        request.sendAsync();
+        h.barrier1().await();
+        // request has been processed
+        CompletableFuture<HttpResponse> cf = request.responseAsync();
+        request.cancel();
+        h.barrier2().await();
+        try {
+            HttpResponse r = cf.get();
+            throw new RuntimeException("failed 2");
+        } catch (Exception e) {
+        }
+        System.out.println(" OK");
+    }
+*/
+    static void delay(int seconds) {
+        try {
+            Thread.sleep(seconds * 1000);
+        } catch (InterruptedException e) {
+        }
+    }
+/*
+    // test won't work until sending fully decoupled from receiving in impl
+    static void test9() throws Exception {
+        System.out.print("test9: ");
+        UploadServer up = new UploadServer(1000 * 1000);
+        int size = up.size();
+        String u = "http://127.0.0.1:" + up.port() + "/";
+        URI uri = new URI(u);
+
+        HttpRequest request = client
+            .request(uri)
+            .body(new HttpRequestBodyProcessor() {
+                @Override
+                public ByteBuffer onRequestBodyChunk(ByteBuffer b) throws IOException {
+                    // slow things down
+                    delay(1);
+                    b.position(b.limit()); // fill it
+                    return b;
+                }
+                @Override
+                public long onRequestStart(HttpRequest req) throws IOException {
+                    return size;
+                }
+             })
+            .PUT();
+
+        CompletableFuture<HttpRequest> cf1 = request.sendAsync();
+        CompletableFuture<HttpResponse> cf = request.responseAsync();
+
+        HttpResponse resp = cf.get(1, TimeUnit.MINUTES);
+        if (resp.statusCode() != 201) {
+            throw new RuntimeException("failed: wrong response code");
+        }
+        delay(2); // allow some data to be sent
+        request.cancel();
+        delay(1);
+        if (up.failed()) {
+            throw new RuntimeException("failed to cancel request");
+        }
+        System.out.println(" OK");
+    }
+  */
+    // Redirect loop: return an error after a certain number of redirects
+    static void test10(String s) throws Exception {
+        System.out.print("test10: " + s);
+        URI uri = new URI(s);
+        RedirectErrorHandler handler = uri.getScheme().equals("https")
+                ? redirectErrorHandlerSecure : redirectErrorHandler;
+
+        CompletableFuture<HttpResponse> cf = client.request(uri)
+                                                   .body(noBody())
+                                                   .GET()
+                                                   .responseAsync();
+
+        try {
+            HttpResponse response = cf.join();
+            throw new RuntimeException("Exepected Completion Exception");
+        } catch (CompletionException e) {
+            //System.out.println(e);
+        }
+
+        System.out.printf(" (Calls %d) ", handler.count());
+        System.out.println(" OK");
+    }
+
+    static final int NUM = 50;
+
+    static Random random = new Random();
+    static final String alphabet = "ABCDEFGHIJKLMNOPQRST";
+
+    static char randomChar() {
+        return alphabet.charAt(random.nextInt(alphabet.length()));
+    }
+
+    static String generateString(int length) {
+        StringBuilder sb = new StringBuilder(length);
+        for (int i=0; i<length; i++) {
+            sb.append(randomChar());
+        }
+        return sb.toString();
+    }
+
+    static void initServer() throws Exception {
+        Logger logger = Logger.getLogger("com.sun.net.httpserver");
+        ConsoleHandler ch = new ConsoleHandler();
+        logger.setLevel(Level.ALL);
+        ch.setLevel(Level.ALL);
+        logger.addHandler(ch);
+
+        String root = System.getProperty ("test.src")+ "/docs";
+        InetSocketAddress addr = new InetSocketAddress (0);
+        s1 = HttpServer.create (addr, 0);
+        if (s1 instanceof HttpsServer) {
+            throw new RuntimeException ("should not be httpsserver");
+        }
+        s2 = HttpsServer.create (addr, 0);
+        HttpHandler h = new FileServerHandler(root);
+
+        HttpContext c1 = s1.createContext("/files", h);
+        HttpContext c2 = s2.createContext("/files", h);
+        HttpContext c3 = s1.createContext("/echo", new EchoHandler());
+        redirectHandler = new RedirectHandler("/redirect");
+        redirectHandlerSecure = new RedirectHandler("/redirect");
+        HttpContext c4 = s1.createContext("/redirect", redirectHandler);
+        HttpContext c41 = s2.createContext("/redirect", redirectHandlerSecure);
+        HttpContext c5 = s2.createContext("/echo", new EchoHandler());
+        HttpContext c6 = s1.createContext("/keepalive", new KeepAliveHandler());
+        redirectErrorHandler = new RedirectErrorHandler("/redirecterror");
+        redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror");
+        HttpContext c7 = s1.createContext("/redirecterror", redirectErrorHandler);
+        HttpContext c71 = s2.createContext("/redirecterror", redirectErrorHandlerSecure);
+        delayHandler = new DelayHandler();
+        HttpContext c8 = s1.createContext("/delay", delayHandler);
+        HttpContext c81 = s2.createContext("/delay", delayHandler);
+
+        executor = Executors.newCachedThreadPool();
+        s1.setExecutor(executor);
+        s2.setExecutor(executor);
+        ctx = new SimpleSSLContext().get();
+        s2.setHttpsConfigurator(new HttpsConfigurator(ctx));
+        s1.start();
+        s2.start();
+
+        port = s1.getAddress().getPort();
+        System.out.println("HTTP server port = " + port);
+        httpsport = s2.getAddress().getPort();
+        System.out.println("HTTPS server port = " + httpsport);
+        httproot = "http://127.0.0.1:" + port + "/";
+        httpsroot = "https://127.0.0.1:" + httpsport + "/";
+
+        proxy = new ProxyServer(0, false);
+        proxyPort = proxy.getPort();
+        System.out.println("Proxy port = " + proxyPort);
+    }
+}
+
+class UploadServer extends Thread {
+    int statusCode;
+    ServerSocket ss;
+    int port;
+    int size;
+    Object lock;
+    boolean failed = false;
+
+    UploadServer(int size) throws IOException {
+        this.statusCode = statusCode;
+        this.size = size;
+        ss = new ServerSocket(0);
+        port = ss.getLocalPort();
+        lock = new Object();
+    }
+
+    int port() {
+          return port;
+    }
+
+    int size() {
+          return size;
+    }
+
+    // wait a sec before calling this
+    boolean failed() {
+        synchronized(lock) {
+            return failed;
+        }
+    }
+
+    @Override
+    public void run () {
+        int nbytes = 0;
+        Socket s = null;
+
+        synchronized(lock) {
+            try {
+                s = ss.accept();
+
+                InputStream is = s.getInputStream();
+                OutputStream os = s.getOutputStream();
+                os.write("HTTP/1.1 201 OK\r\nContent-length: 0\r\n\r\n".getBytes());
+                int n;
+                byte[] buf = new byte[8000];
+                while ((n=is.read(buf)) != -1) {
+                    nbytes += n;
+                }
+            } catch (IOException e) {
+                System.out.println ("read " + nbytes);
+                System.out.println ("size " + size);
+                failed = nbytes >= size;
+            } finally {
+                try {
+                    ss.close();
+                    if (s != null)
+                        s.close();
+                } catch (IOException e) {}
+            }
+        }
+    }
+}
+
+class RedirectHandler implements HttpHandler {
+    String root;
+    volatile int count = 0;
+
+    RedirectHandler(String root) {
+        this.root = root;
+    }
+
+    @Override
+    public synchronized void handle(HttpExchange t)
+        throws IOException
+    {
+        byte[] buf = new byte[2048];
+        try (InputStream is = t.getRequestBody()) {
+            while (is.read(buf) != -1) ;
+        }
+
+        Headers responseHeaders = t.getResponseHeaders();
+
+        if (count++ < 1) {
+            responseHeaders.add("Location", root + "/foo/" + count);
+        } else {
+            responseHeaders.add("Location", SmokeTest.midSizedFilename);
+        }
+        t.sendResponseHeaders(301, -1);
+        t.close();
+    }
+
+    int count() {
+        return count;
+    }
+
+    void reset() {
+        count = 0;
+    }
+}
+
+class RedirectErrorHandler implements HttpHandler {
+    String root;
+    volatile int count = 1;
+
+    RedirectErrorHandler(String root) {
+        this.root = root;
+    }
+
+    synchronized int count() {
+        return count;
+    }
+
+    synchronized void increment() {
+        count++;
+    }
+
+    @Override
+    public synchronized void handle (HttpExchange t)
+        throws IOException
+    {
+        byte[] buf = new byte[2048];
+        try (InputStream is = t.getRequestBody()) {
+            while (is.read(buf) != -1) ;
+        }
+
+        Headers map = t.getResponseHeaders();
+        String redirect = root + "/foo/" + Integer.toString(count);
+        increment();
+        map.add("Location", redirect);
+        t.sendResponseHeaders(301, -1);
+        t.close();
+    }
+}
+
+class Util {
+    static byte[] readAll(InputStream is) throws IOException {
+        byte[] buf = new byte[1024];
+        byte[] result = new byte[0];
+
+        while (true) {
+            int n = is.read(buf);
+            if (n > 0) {
+                byte[] b1 = new byte[result.length + n];
+                System.arraycopy(result, 0, b1, 0, result.length);
+                System.arraycopy(buf, 0, b1, result.length, n);
+                result = b1;
+            } else if (n == -1) {
+                return result;
+            }
+        }
+    }
+}
+
+class DelayHandler implements HttpHandler {
+
+    CyclicBarrier bar1 = new CyclicBarrier(2);
+    CyclicBarrier bar2 = new CyclicBarrier(2);
+    CyclicBarrier bar3 = new CyclicBarrier(2);
+
+    CyclicBarrier barrier1() {
+        return bar1;
+    }
+
+    CyclicBarrier barrier2() {
+        return bar2;
+    }
+
+    @Override
+    public synchronized void handle(HttpExchange he) throws IOException {
+        byte[] buf = Util.readAll(he.getRequestBody());
+        try {
+            bar1.await();
+            bar2.await();
+        } catch (Exception e) {}
+        he.sendResponseHeaders(200, -1); // will probably fail
+        he.close();
+    }
+
+}
+
+// check for simple hardcoded sequence and use remote address
+// to check.
+// First 4 requests executed in sequence (should use same connection/address)
+// Next 4 requests parallel (should use different addresses)
+// Then send 4 requests in parallel x 100 times (same four addresses used all time)
+
+class KeepAliveHandler implements HttpHandler {
+    volatile int counter = 0;
+
+    HashSet<Integer> portSet = new HashSet<>();
+
+    volatile int[] ports = new int[4];
+
+    void sleep(int n) {
+        try {
+            Thread.sleep(n);
+        } catch (InterruptedException e) {}
+    }
+
+    @Override
+    public synchronized void handle (HttpExchange t)
+        throws IOException
+    {
+        int remotePort = t.getRemoteAddress().getPort();
+        String result = "OK";
+
+        int n = counter++;
+        /// First test
+        if (n < 4) {
+            ports[n] = remotePort;
+        }
+        if (n == 3) {
+            // check all values in ports[] are the same
+            if (ports[0] != ports[1] || ports[2] != ports[3]
+                    || ports[0] != ports[2]) {
+                result = "Error " + Integer.toString(n);
+                System.out.println(result);
+            }
+        }
+        // Second test
+        if (n >=4 && n < 8) {
+            // delay to ensure ports are different
+            sleep(500);
+            ports[n-4] = remotePort;
+        }
+        if (n == 7) {
+            // should be all different
+            if (ports[0] == ports[1] || ports[2] == ports[3]
+                    || ports[0] == ports[2]) {
+                result = "Error " + Integer.toString(n);
+                System.out.println(result);
+                System.out.printf("Ports: %d, %d, %d, %d\n", ports[0], ports[1], ports[2], ports[3]);
+            }
+            // setup for third test
+            for (int i=0; i<4; i++) {
+                portSet.add(ports[i]);
+            }
+        }
+        // Third test
+        if (n > 7) {
+            // just check that port is one of the ones in portSet
+            if (!portSet.contains(remotePort)) {
+                System.out.println ("UNEXPECTED REMOTE PORT " + remotePort);
+                result = "Error " + Integer.toString(n);
+                System.out.println(result);
+            }
+        }
+        byte[] buf = new byte[2048];
+
+        try (InputStream is = t.getRequestBody()) {
+            while (is.read(buf) != -1) ;
+        }
+        t.sendResponseHeaders(200, result.length());
+        OutputStream o = t.getResponseBody();
+        o.write(result.getBytes("US-ASCII"));
+        t.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/SplitResponse.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+//package javaapplication16;
+
+import java.io.IOException;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @test
+ * @bug 8087112
+ * @build Server
+ * @run main/othervm -Djava.net.HttpClient.log=all SplitResponse
+ */
+
+/**
+ * Similar test to QuickResponses except that each byte of the response
+ * is sent in a separate packet, which tests the stability of the implementation
+ * for receiving unusual packet sizes.
+ */
+public class SplitResponse {
+
+    static Server server;
+
+    static String response(String body) {
+        return "HTTP/1.1 200 OK\r\nConnection: Close\r\nContent-length: "
+                + Integer.toString(body.length())
+                + "\r\n\r\n" + body;
+    }
+
+    static final String responses[] = {
+        "Lorem ipsum",
+        "dolor sit amet",
+        "consectetur adipiscing elit, sed do eiusmod tempor",
+        "quis nostrud exercitation ullamco",
+        "laboris nisi",
+        "ut",
+        "aliquip ex ea commodo consequat." +
+        "Duis aute irure dolor in reprehenderit in voluptate velit esse" +
+        "cillum dolore eu fugiat nulla pariatur.",
+        "Excepteur sint occaecat cupidatat non proident."
+    };
+
+    public static void main(String[] args) throws Exception {
+        server = new Server(0);
+        URI uri = new URI(server.getURL());
+
+        HttpRequest request;
+        HttpResponse r;
+        CompletableFuture<HttpResponse> cf1;
+
+        for (int i=0; i<responses.length; i++) {
+            cf1 = HttpRequest.create(uri)
+                    .GET()
+                    .responseAsync();
+            String body = responses[i];
+
+            Server.Connection c = server.activity();
+            sendSplitResponse(response(body), c);
+            r = cf1.get();
+            if (r.statusCode()!= 200)
+                throw new RuntimeException("Failed");
+
+            String rxbody = r.body(HttpResponse.asString());
+            System.out.println("received " + rxbody);
+            if (!rxbody.equals(body))
+                throw new RuntimeException("Failed");
+            c.close();
+        }
+        HttpClient.getDefault().executorService().shutdownNow();
+        System.out.println("OK");
+    }
+
+    // send the response one byte at a time with a small delay between bytes
+    // to ensure that each byte is read in a separate read
+    static void sendSplitResponse(String s, Server.Connection conn) {
+        System.out.println("Sending: ");
+        Thread t = new Thread(() -> {
+            try {
+                int len = s.length();
+                for (int i = 0; i < len; i++) {
+                    String onechar = s.substring(i, i + 1);
+                    conn.send(onechar);
+                    Thread.sleep(30);
+                }
+                System.out.println("sent");
+            } catch (IOException | InterruptedException e) {
+            }
+        });
+        t.setDaemon(true);
+        t.start();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/TimeoutTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.http.HttpTimeoutException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @test
+ * @bug 8087112
+ * @run main/othervm TimeoutTest
+ */
+
+public class TimeoutTest {
+
+    static int[] timeouts = {6, 4, 8, 6, 6, 4};
+    static HttpRequest[] rqs = new HttpRequest[timeouts.length];
+    static LinkedBlockingQueue<HttpRequest> queue = new LinkedBlockingQueue<>();
+    static volatile boolean error = false;
+    static ExecutorService executor = Executors.newCachedThreadPool();
+
+    public static void main(String[] args) throws Exception {
+        try {
+            dotest();
+        } finally {
+            HttpClient.getDefault().executorService().shutdownNow();
+            executor.shutdownNow();
+        }
+    }
+    public static void dotest() throws Exception {
+        System.out.println("Test takes over 40 seconds");
+        ServerSocket ss = new ServerSocket(0, 20);
+        int port = ss.getLocalPort();
+
+        URI uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/foo");
+        int i = 0;
+        for (int timeout : timeouts) {
+            HttpRequest request;
+            (request = rqs[i] = HttpRequest.create(uri)
+                .timeout(TimeUnit.SECONDS, timeout)
+                .GET())
+                .responseAsync()
+                .whenComplete((HttpResponse r, Throwable t) -> {
+                    if (!(t.getCause() instanceof HttpTimeoutException)) {
+                        System.out.println("Wrong exception type:" + t.toString());
+                        error = true;
+                    }
+                    if (t != null) {
+                        queue.add(request);
+                    }
+                })
+                .thenAccept((HttpResponse r) -> {
+                    r.bodyAsync(HttpResponse.ignoreBody());
+                });
+            i++;
+        }
+
+        System.out.println("SUBMITTED");
+
+        checkReturnOrder();
+
+        if (error)
+            throw new RuntimeException("Failed");
+
+        // Repeat blocking in separate threads. Use queue to wait.
+        System.out.println("DOING BLOCKING");
+
+        i = 0;
+        for (int timeout : timeouts) {
+            HttpRequest req = HttpRequest.create(uri)
+                .timeout(TimeUnit.SECONDS, timeout)
+                .GET();
+            rqs[i] = req;
+            executor.execute(() -> {
+                try {
+                    req.response().body(HttpResponse.ignoreBody());
+                } catch (HttpTimeoutException e) {
+                    queue.offer(req);
+                } catch (IOException | InterruptedException ee) {
+                    error = true;
+                }
+            });
+            i++;
+        }
+
+        checkReturnOrder();
+
+        if (error)
+            throw new RuntimeException("Failed");
+    }
+
+    static void checkReturnOrder() throws InterruptedException {
+        // wait for exceptions and check order
+        for (int j = 0; j < timeouts.length; j++) {
+            HttpRequest req = queue.take();
+            switch (j) {
+                case 0:
+                case 1:
+                    if (req != rqs[1] && req != rqs[5]) {
+                        System.out.printf("Expected 1 or 5. Got %s\n", getRequest(req));
+                        throw new RuntimeException("Error");
+                    }
+                    break;
+                case 2:
+                case 3:
+                case 4:
+                    if (req != rqs[0] && req != rqs[3] && req != rqs[4]) {
+                        System.out.printf("Expected r1, r4 or r5. Got %s\n", getRequest(req));
+                        throw new RuntimeException("Error");
+                    }
+                    break;
+                case 5:
+                    if (req != rqs[2]) {
+                        System.out.printf("Expected r3. Got %s\n", getRequest(req));
+                        throw new RuntimeException("Error");
+                    }
+            }
+        }
+        System.out.println("Return order ok");
+    }
+
+    static String getRequest(HttpRequest req) {
+        for (int i=0; i<rqs.length; i++) {
+            if (req == rqs[i]) {
+                return "[" + Integer.toString(i) + "]";
+            }
+        }
+        return "unknown";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/docs/files/foo.txt	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,1 @@
+This is foo.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/docs/files/notsobigfile.txt	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/docs/files/smallfile.txt	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,1792 @@
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/0.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy: 0
+
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/1.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 1
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/10.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,22 @@
+// Policy 10
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/11.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 11
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+    permission java.net.URLPermission "socket://127.0.0.1:27301", "CONNECT";
+};
+
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/12.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 11
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+    permission java.net.URLPermission "socket://127.0.0.1:27301", "CONNECT";
+};
+
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/15.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,27 @@
+// Policy 11
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+    permission java.net.URLPermission "socket://127.0.0.1:27301", "CONNECT";
+
+    // Test checks for this explicitly
+    permission java.net.RuntimePermission "foobar"; 
+};
+
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/2.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 2
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/*", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/3.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 3
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/redirect/foo.txt", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/4.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,25 @@
+// Policy 4
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/redirect/foo.txt", "GET";
+    permission java.net.URLPermission "http://127.0.0.1:*/redirect/bar.txt", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/5.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 5
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/redirect/bar.txt", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/6.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 6
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "POST";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/7.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 7
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:X-Bar";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/8.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 8
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:X-Foo1,X-Foo,X-Bar";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/9.policy	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,24 @@
+// Policy 9
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/Security.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,475 @@
+/*
+ * 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
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext
+ * @compile ../../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../../com/sun/net/httpserver/FileServerHandler.java
+ * @compile ../ProxyServer.java
+ *
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=0.policy Security 0
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=1.policy Security 1
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=2.policy Security 2
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=3.policy Security 3
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=4.policy Security 4
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=5.policy Security 5
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=6.policy Security 6
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=7.policy Security 7
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=8.policy Security 8
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=9.policy Security 9
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=10.policy Security 10
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=11.policy Security 11
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=12.policy Security 12
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=0.policy Security 13
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=1.policy Security 14
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=15.policy Security 15
+ */
+
+import com.sun.net.httpserver.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.net.*;
+import java.net.http.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.ByteBuffer;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.function.*;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Security checks test
+ */
+public class Security {
+
+    static HttpServer s1 = null;
+    static ExecutorService executor=null;
+    static int port;
+    static HttpClient client;
+    static String httproot, fileuri, fileroot, redirectroot;
+    static List<HttpClient> clients = new LinkedList<>();
+    static URI uri;
+
+    interface Test {
+        public void execute() throws IOException, InterruptedException;
+    }
+
+    static class TestAndResult {
+        Test test;
+        boolean result;
+
+        TestAndResult (Test t, boolean result) {
+            this.test = t;
+            this.result = result;
+        }
+    }
+
+    static TestAndResult test(boolean result, Test t) {
+        return new TestAndResult(t, result);
+    }
+
+    static TestAndResult[] tests;
+    static String testclasses;
+    static File subdir;
+
+    /**
+     * The ProxyServer class is compiled by jtreg, but we want to
+     * move it so it is not on the application claspath. We want to
+     * load it through a separate classloader so that it has a separate
+     * protection domain and security permissions.
+     *
+     * Its permissions are in the second grant block in each policy file
+     */
+    static void setupProxy() throws IOException, ClassNotFoundException, NoSuchMethodException {
+        testclasses = System.getProperty("test.classes");
+        subdir = new File (testclasses, "proxydir");
+        subdir.mkdir();
+
+        movefile("ProxyServer.class");
+        movefile("ProxyServer$Connection.class");
+        movefile("ProxyServer$1.class");
+
+        URL url = subdir.toURL();
+        System.out.println("URL for class loader = " + url);
+        URLClassLoader urlc = new URLClassLoader(new URL[] {url});
+        proxyClass = Class.forName("ProxyServer", true, urlc);
+        proxyConstructor = proxyClass.getConstructor(Integer.class, Boolean.class);
+    }
+
+    static void movefile(String f) throws IOException {
+        Path src = Paths.get(testclasses, f);
+        Path dest = subdir.toPath().resolve(f);
+        if (!dest.toFile().exists()) {
+            System.out.printf("moving %s to %s\n", src.toString(), dest.toString());
+            Files.move(src, dest,  StandardCopyOption.REPLACE_EXISTING);
+        } else {
+            System.out.printf("NOT moving %s to %s\n", src.toString(), dest.toString());
+        }
+    }
+
+    static Object getProxy(int port, boolean b) throws Exception {
+        return proxyConstructor.newInstance(port, b);
+    }
+
+    static Class<?> proxyClass;
+    static Constructor<?> proxyConstructor;
+
+    static void setupTests() {
+        tests = new TestAndResult[]{
+            // (0) policy does not have permission for file. Should fail
+            test(false, () -> { // Policy 0
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (1) policy has permission for file URL
+            test(true, () -> { //Policy 1
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (2) policy has permission for all file URLs under /files
+            test(true, () -> { // Policy 2
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (3) policy has permission for first URL but not redirected URL
+            test(false, () -> { // Policy 3
+                URI u = URI.create("http://127.0.0.1:" + port + "/redirect/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (4) policy has permission for both first URL and redirected URL
+            test(true, () -> { // Policy 4
+                URI u = URI.create("http://127.0.0.1:" + port + "/redirect/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (5) policy has permission for redirected but not first URL
+            test(false, () -> { // Policy 5
+                URI u = URI.create("http://127.0.0.1:" + port + "/redirect/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (6) policy has permission for file URL, but not method
+            test(false, () -> { //Policy 6
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (7) policy has permission for file URL, method, but not header
+            test(false, () -> { //Policy 7
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .header("X-Foo", "bar")
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (8) policy has permission for file URL, method and header
+            test(true, () -> { //Policy 8
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .header("X-Foo", "bar")
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (9) policy has permission for file URL, method and header
+            test(true, () -> { //Policy 9
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .headers("X-Foo", "bar", "X-Bar", "foo")
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (10) policy has permission for destination URL but not for proxy
+            test(false, () -> { //Policy 10
+                directProxyTest(27208, true);
+            }),
+            // (11) policy has permission for both destination URL and proxy
+            test(true, () -> { //Policy 11
+                directProxyTest(27301, true);
+            }),
+            // (12) policy has permission for both destination URL and proxy
+            test(false, () -> { //Policy 11
+                directProxyTest(28301, false);
+            }),
+            // (13) async version of test 0
+            test(false, () -> { // Policy 0
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                try {
+                    HttpResponse response = request.responseAsync().get();
+                } catch (ExecutionException e) {
+                    if (e.getCause() instanceof SecurityException) {
+                        throw (SecurityException)e.getCause();
+                    } else {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }),
+            // (14) async version of test 1
+            test(true, () -> { //Policy 1
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                try {
+                    HttpResponse response = request.responseAsync().get();
+                } catch (ExecutionException e) {
+                    if (e.getCause() instanceof SecurityException) {
+                        throw (SecurityException)e.getCause();
+                    } else {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }),
+            // (15) check that user provided unprivileged code running on a worker
+            //      thread does not gain ungranted privileges.
+            test(false, () -> { //Policy 12
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+                HttpResponse.BodyProcessor<String> stproc = HttpResponse.asString();
+
+                CompletableFuture<String> cf;
+                cf = response.bodyAsync(new HttpResponse.BodyProcessor<String>() {
+                        public void onResponseBodyChunk(ByteBuffer b) throws IOException {
+                            // do some mischief here
+                            SecurityManager sm = System.getSecurityManager();
+                            System.setSecurityManager(null);
+                            System.setSecurityManager(sm);
+                            // problem if we get this far
+                            stproc.onResponseBodyChunk(b);
+                        }
+                        public String onResponseBodyStart(long contentLength,
+                                        HttpHeaders responseHeaders,
+                                        LongConsumer fc) throws IOException {
+
+                            SecurityManager sm = System.getSecurityManager();
+                            // should succeed.
+                            sm.checkPermission(new RuntimePermission("foobar"));
+                            return stproc.onResponseBodyStart(contentLength,responseHeaders, fc);
+                        }
+                        public String onResponseComplete() throws IOException {
+                            return stproc.onResponseComplete();
+                        }
+                        public void onResponseError(Throwable t) {
+                            stproc.onResponseError(t);
+                        }
+                    }
+                );
+                try {
+                    System.out.println("Body = " + cf.get());// should not reach here
+                } catch (ExecutionException e) {
+                    if (e.getCause() instanceof SecurityException) {
+                        throw (SecurityException)e.getCause();
+                    } else {
+                        throw new RuntimeException(e);
+                    }
+                }
+            })
+        };
+    }
+
+    private static void directProxyTest(int proxyPort, boolean samePort) throws IOException, InterruptedException {
+        Object proxy = null;
+        try {
+            proxy = getProxy(proxyPort, true);
+        } catch (IOException e) {
+            System.out.println("Cannot bind. Not running test");
+            throw new SecurityException("test not run");
+        } catch (Exception ee) {
+            throw new RuntimeException(ee);
+        }
+        System.out.println("Proxy port = " + proxyPort);
+        if (!samePort)
+            proxyPort++;
+
+        HttpClient cl = HttpClient.create()
+                .proxy(ProxySelector.of(
+                                new InetSocketAddress("127.0.0.1", proxyPort)))
+                .build();
+        clients.add(cl);
+
+        URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+        HttpRequest request = cl.request(u)
+                .headers("X-Foo", "bar", "X-Bar", "foo")
+                .GET();
+        HttpResponse response = request.response();
+    }
+
+    static void runtest(Test r, String policy, boolean succeeds) {
+        System.out.println("Using policy file: " + policy);
+        try {
+            r.execute();
+            if (!succeeds) {
+                System.out.println("FAILED: expected security exception");
+                throw new RuntimeException("Failed");
+            }
+            System.out.println (policy + " succeeded as expected");
+        } catch (SecurityException e) {
+            if (succeeds) {
+                System.out.println("FAILED");
+                throw new RuntimeException(e);
+            }
+            System.out.println (policy + " threw exception as expected");
+        } catch (IOException | InterruptedException ee) {
+            throw new RuntimeException(ee);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        initServer();
+        setupProxy();
+        fileroot = System.getProperty ("test.src")+ "/docs";
+        int testnum = Integer.parseInt(args[0]);
+        String policy = args[0];
+
+        client = HttpClient
+            .create()
+            .followRedirects(HttpClient.Redirect.ALWAYS)
+            .build();
+
+        clients.add(HttpClient.getDefault());
+        clients.add(client);
+
+        try {
+            setupTests();
+            TestAndResult tr = tests[testnum];
+            runtest(tr.test, policy, tr.result);
+        } finally {
+            s1.stop(0);
+            //executor.shutdownNow();
+            for (HttpClient client : clients)
+                client.executorService().shutdownNow();
+        }
+    }
+
+    // create Http Server on port range below. So, we can
+    HttpServer createServer() {
+        HttpServer server;
+        for (int i=25800; i<26800; i++) {
+            InetSocketAddress a = new InetSocketAddress(i);
+            try {
+                server = HttpServer.create(a, 0);
+                return server;
+            } catch (IOException e) {}
+        }
+        return null;
+    }
+
+    public static void initServer() throws Exception {
+        Logger logger = Logger.getLogger("com.sun.net.httpserver");
+        ConsoleHandler ch = new ConsoleHandler();
+        logger.setLevel(Level.ALL);
+        ch.setLevel(Level.ALL);
+        logger.addHandler(ch);
+        String root = System.getProperty ("test.src")+ "/docs";
+        InetSocketAddress addr = new InetSocketAddress (0);
+        s1 = HttpServer.create (addr, 0);
+        if (s1 instanceof HttpsServer) {
+            throw new RuntimeException ("should not be httpsserver");
+        }
+        HttpHandler h = new FileServerHandler (root);
+        HttpContext c = s1.createContext ("/files", h);
+
+        HttpHandler h1 = new RedirectHandler ("/redirect");
+        HttpContext c1 = s1.createContext ("/redirect", h1);
+
+        executor = Executors.newCachedThreadPool();
+        s1.setExecutor (executor);
+        s1.start();
+
+        port = s1.getAddress().getPort();
+        System.out.println("HTTP server port = " + port);
+        httproot = "http://127.0.0.1:" + port + "/files/";
+        redirectroot = "http://127.0.0.1:" + port + "/redirect/";
+        uri = new URI(httproot);
+        fileuri = httproot + "foo.txt";
+    }
+
+    static class RedirectHandler implements HttpHandler {
+
+        String root;
+        int count = 0;
+
+        RedirectHandler(String root) {
+            this.root = root;
+        }
+
+        synchronized int count() {
+            return count;
+        }
+
+        synchronized void increment() {
+            count++;
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange t)
+                throws IOException {
+            byte[] buf = new byte[2048];
+            System.out.println("Server: " + t.getRequestURI());
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read(buf) != -1) ;
+            }
+            increment();
+            if (count() == 1) {
+                Headers map = t.getResponseHeaders();
+                String redirect = "/redirect/bar.txt";
+                map.add("Location", redirect);
+                t.sendResponseHeaders(301, -1);
+                t.close();
+            } else {
+                String response = "Hello world";
+                t.sendResponseHeaders(200, response.length());
+                OutputStream os = t.getResponseBody();
+                os.write(response.getBytes(StandardCharsets.ISO_8859_1));
+                t.close();
+            }
+        }
+    }
+}
--- a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, 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
@@ -141,8 +141,11 @@
         try {
             // check supported options
             Set<SocketOption<?>> options = ch.supportedOptions();
+            boolean reuseport = options.contains(SO_REUSEPORT);
             if (!options.contains(SO_REUSEADDR))
                 throw new RuntimeException("SO_REUSEADDR should be supported");
+            if (!options.contains(SO_REUSEPORT) && reuseport)
+                throw new RuntimeException("SO_REUSEPORT should be supported");
             if (!options.contains(SO_RCVBUF))
                 throw new RuntimeException("SO_RCVBUF should be supported");
 
@@ -156,6 +159,13 @@
             checkOption(ch, SO_REUSEADDR, true);
             ch.setOption(SO_REUSEADDR, false);
             checkOption(ch, SO_REUSEADDR, false);
+
+            if (reuseport) {
+                ch.setOption(SO_REUSEPORT, true);
+                checkOption(ch, SO_REUSEPORT, true);
+                ch.setOption(SO_REUSEPORT, false);
+                checkOption(ch, SO_REUSEPORT, false);
+            }
         } finally {
             ch.close();
         }
--- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, 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
@@ -37,6 +37,7 @@
 import java.util.concurrent.atomic.*;
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.Set;
 
 public class Basic {
     static final Random rand = new Random();
@@ -165,6 +166,15 @@
             // read others (can't check as actual value is implementation dependent)
             ch.getOption(SO_RCVBUF);
             ch.getOption(SO_SNDBUF);
+
+            Set<SocketOption<?>> options = ch.supportedOptions();
+            boolean reuseport = options.contains(SO_REUSEPORT);
+            if (reuseport) {
+                if (ch.getOption(SO_REUSEPORT))
+                    throw new RuntimeException("Default of SO_REUSEPORT should be 'false'");
+                if (!ch.setOption(SO_REUSEPORT, true).getOption(SO_REUSEPORT))
+                    throw new RuntimeException("SO_REUSEPORT did not change");
+            }
         }
     }
 
--- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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,9 +50,17 @@
 
         // check supported options
         Set<SocketOption<?>> options = dc.supportedOptions();
-        List<? extends SocketOption<?>> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
-            SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL,
-            IP_MULTICAST_LOOP);
+        boolean reuseport = options.contains(SO_REUSEPORT);
+        List<? extends SocketOption<?>> expected;
+        if (reuseport) {
+           expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
+                      SO_REUSEADDR, SO_REUSEPORT, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF,
+                      IP_MULTICAST_TTL, IP_MULTICAST_LOOP);
+        } else {
+           expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
+                      SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL,
+                      IP_MULTICAST_LOOP);
+        }
         for (SocketOption opt: expected) {
             if (!options.contains(opt))
                 throw new RuntimeException(opt.name() + " should be supported");
@@ -83,7 +91,12 @@
         checkOption(dc, SO_REUSEADDR, true);
         dc.setOption(SO_REUSEADDR, false);
         checkOption(dc, SO_REUSEADDR, false);
-
+        if (reuseport) {
+            dc.setOption(SO_REUSEPORT, true);
+            checkOption(dc, SO_REUSEPORT, true);
+            dc.setOption(SO_REUSEPORT, false);
+            checkOption(dc, SO_REUSEPORT, false);
+        }
         // bind socket
         dc.bind(new InetSocketAddress(0));
 
--- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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,8 +49,11 @@
 
         // check supported options
         Set<SocketOption<?>> options = ssc.supportedOptions();
+        boolean reuseport = options.contains(SO_REUSEPORT);
         if (!options.contains(SO_REUSEADDR))
             throw new RuntimeException("SO_REUSEADDR should be supported");
+        if (!options.contains(SO_REUSEPORT) && reuseport)
+            throw new RuntimeException("SO_REUSEPORT should be supported");
         if (!options.contains(SO_RCVBUF))
             throw new RuntimeException("SO_RCVBUF should be supported");
 
@@ -64,6 +67,12 @@
         checkOption(ssc, SO_REUSEADDR, true);
         ssc.setOption(SO_REUSEADDR, false);
         checkOption(ssc, SO_REUSEADDR, false);
+        if (reuseport) {
+            ssc.setOption(SO_REUSEPORT, true);
+            checkOption(ssc, SO_REUSEPORT, true);
+            ssc.setOption(SO_REUSEPORT, false);
+            checkOption(ssc, SO_REUSEPORT, false);
+        }
 
         // NullPointerException
         try {
--- a/jdk/test/java/nio/charset/coders/BashStreams.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/nio/charset/coders/BashStreams.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 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
@@ -23,7 +23,7 @@
 
 /* @test
  * @summary Stochastic test of charset-based streams
- * @key randomness
+ * @key randomness intermittent
  */
 
 import java.io.*;
--- a/jdk/test/java/nio/file/Files/probeContentType/Basic.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/nio/file/Files/probeContentType/Basic.java	Wed Jul 05 21:24:14 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
@@ -29,8 +29,9 @@
  * @run main/othervm Basic
  */
 
+import java.io.*;
 import java.nio.file.*;
-import java.io.*;
+import java.util.stream.Stream;
 
 /**
  * Uses Files.probeContentType to probe html file, custom file type, and minimal
@@ -38,6 +39,9 @@
  */
 public class Basic {
 
+    private static final boolean IS_UNIX =
+        ! System.getProperty("os.name").startsWith("Windows");
+
     static Path createHtmlFile() throws IOException {
         Path file = Files.createTempFile("foo", ".html");
         try (OutputStream out = Files.newOutputStream(file)) {
@@ -51,10 +55,61 @@
         return Files.createTempFile("red", ".grape");
     }
 
-    static void checkContentTypes(String[] extensions, String[] expectedTypes)
+    private static int checkContentTypes(String expected, String actual) {
+        assert expected != null;
+        assert actual != null;
+
+        if (!expected.equals(actual)) {
+            if (IS_UNIX) {
+                Path userMimeTypes =
+                    Paths.get(System.getProperty("user.home"), ".mime.types");
+                if (!Files.exists(userMimeTypes)) {
+                    System.out.println(userMimeTypes + " does not exist");
+                } else if (!Files.isReadable(userMimeTypes)) {
+                    System.out.println(userMimeTypes + " is not readable");
+                } else {
+                    System.out.println(userMimeTypes + " contents:");
+                    try (Stream<String> lines = Files.lines(userMimeTypes)) {
+                        lines.forEach(System.out::println);
+                        System.out.println("");
+                    } catch (IOException ioe) {
+                        System.err.println("Problem reading "
+                                           + userMimeTypes);
+                    }
+                }
+
+                Path etcMimeTypes = Paths.get("/etc/mime.types");
+                if (!Files.exists(etcMimeTypes)) {
+                    System.out.println(etcMimeTypes + " does not exist");
+                } else if (!Files.isReadable(etcMimeTypes)) {
+                    System.out.println(etcMimeTypes + " is not readable");
+                } else {
+                    System.out.println(etcMimeTypes + " contents:");
+                    try (Stream<String> lines = Files.lines(etcMimeTypes)) {
+                        lines.forEach(System.out::println);
+                        System.out.println("");
+                    } catch (IOException ioe) {
+                        System.err.println("Problem reading "
+                                           + etcMimeTypes);
+                    }
+                }
+            }
+
+            System.err.println("Expected \"" + expected
+                               + "\" but obtained \""
+                               + actual + "\"");
+
+            return 1;
+        }
+
+        return 0;
+    }
+
+    static int checkOSXContentTypes(String[] extensions, String[] expectedTypes)
         throws IOException {
         if (extensions.length != expectedTypes.length) {
-            throw new IllegalArgumentException("Parameter array lengths differ");
+            throw new IllegalArgumentException
+                ("Parameter array lengths differ");
         }
 
         int failures = 0;
@@ -79,12 +134,11 @@
             }
         }
 
-        if (failures > 0) {
-            throw new RuntimeException("Test failed!");
-        }
+        return failures;
     }
 
     public static void main(String[] args) throws IOException {
+        int failures = 0;
 
         // exercise default file type detector
         Path file = createHtmlFile();
@@ -93,8 +147,7 @@
             if (type == null) {
                 System.err.println("Content type cannot be determined - test skipped");
             } else {
-                if (!type.equals("text/html"))
-                    throw new RuntimeException("Unexpected type: " + type);
+                failures += checkContentTypes("text/html", type);
             }
         } finally {
             Files.delete(file);
@@ -106,8 +159,7 @@
             String type = Files.probeContentType(file);
             if (type == null)
                 throw new RuntimeException("Custom file type detector not installed?");
-            if (!type.equals("grape/unknown"))
-                throw new RuntimeException("Unexpected type: " + type);
+            failures += checkContentTypes("grape/unknown", type);
         } finally {
             Files.delete(file);
         }
@@ -122,7 +174,11 @@
                 "image/jpeg", "audio/mpeg", "video/mp4", "application/pdf",
                 "image/png"
             };
-            checkContentTypes(extensions, expectedTypes);
+            failures += checkOSXContentTypes(extensions, expectedTypes);
+        }
+
+        if (failures > 0) {
+            throw new RuntimeException("Test failed!");
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @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 MultiReleaseJarAPI
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static java.util.jar.JarFile.Release;
+import static sun.misc.Version.jdkMajorVersion;  // fixme JEP 223 Version
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+public class MultiReleaseJarAPI {
+    String userdir = System.getProperty("user.dir",".");
+    File unversioned = new File(userdir, "unversioned.jar");
+    File multirelease = new File(userdir, "multi-release.jar");
+    File signedmultirelease = new File(userdir, "signed-multi-release.jar");
+    Release[] values = JarFile.Release.values();
+
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildUnversionedJar();
+        creator.buildMultiReleaseJar();
+        creator.buildSignedMultiReleaseJar();
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        Files.delete(unversioned.toPath());
+        Files.delete(multirelease.toPath());
+        Files.delete(signedmultirelease.toPath());
+    }
+
+    @Test
+    public void isMultiReleaseJar() throws Exception {
+        try (JarFile jf = new JarFile(unversioned)) {
+            Assert.assertFalse(jf.isMultiRelease());
+        }
+
+        try (JarFile jf = new JarFile(multirelease)) {
+            Assert.assertTrue(jf.isMultiRelease());
+        }
+    }
+
+    @Test
+    public void testVersioning() throws Exception {
+        // multi-release jar
+        JarFile jar = new JarFile(multirelease);
+        Assert.assertEquals(Release.BASE, jar.getVersion());
+        jar.close();
+
+        for (Release value : values) {
+            System.err.println("test versioning for Release " + value);
+            try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, value)) {
+                Assert.assertEquals(value, jf.getVersion());
+            }
+        }
+
+        // regular, unversioned, jar
+        for (Release value : values) {
+            try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, value)) {
+                Assert.assertEquals(Release.BASE, jf.getVersion());
+            }
+        }
+
+        // assure that we have a Release object corresponding to the actual runtime version
+        String version = "VERSION_" + jdkMajorVersion();
+        boolean runtimeVersionExists = false;
+        for (Release value : values) {
+            if (version.equals(value.name())) runtimeVersionExists = true;
+        }
+        Assert.assertTrue(runtimeVersionExists);
+    }
+
+    @Test
+    public void testAliasing() throws Exception {
+        for (Release value : values) {
+            System.err.println("test aliasing for Release " + value);
+            String name = value.name();
+            String prefix;
+            if (name.equals("BASE")) {
+                prefix = "";
+            } else if (name.equals("RUNTIME")) {
+                prefix = "META-INF/versions/" + jdkMajorVersion() + "/";
+            } else {
+                prefix = "META-INF/versions/" + name.substring(8) + "/";
+            }
+            // test both multi-release jars
+            readAndCompare(multirelease, value, "README", prefix + "README");
+            readAndCompare(multirelease, value, "version/Version.class", prefix + "version/Version.class");
+            // and signed multi-release jars
+            readAndCompare(signedmultirelease, value, "README", prefix + "README");
+            readAndCompare(signedmultirelease, value, "version/Version.class", prefix + "version/Version.class");
+        }
+    }
+
+    private void readAndCompare(File jar, Release version, String name, String realName) throws Exception {
+        byte[] baseBytes;
+        byte[] versionedBytes;
+        try (JarFile jf = new JarFile(jar, true, ZipFile.OPEN_READ, Release.BASE)) {
+            ZipEntry ze = jf.getEntry(realName);
+            try (InputStream is = jf.getInputStream(ze)) {
+                baseBytes = is.readAllBytes();
+            }
+        }
+        assert baseBytes.length > 0;
+
+        try (JarFile jf = new JarFile(jar, true, ZipFile.OPEN_READ, version)) {
+            ZipEntry ze = jf.getEntry(name);
+            try (InputStream is = jf.getInputStream(ze)) {
+                versionedBytes = is.readAllBytes();
+            }
+        }
+        assert versionedBytes.length > 0;
+
+        Assert.assertTrue(Arrays.equals(baseBytes, versionedBytes));
+    }
+
+    @Test
+    public void testNames() throws Exception {
+        String rname = "version/Version.class";
+        String vname = "META-INF/versions/9/version/Version.class";
+        ZipEntry ze1;
+        ZipEntry ze2;
+        try (JarFile jf = new JarFile(multirelease)) {
+            ze1 = jf.getEntry(vname);
+        }
+        Assert.assertEquals(ze1.getName(), vname);
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+            ze2 = jf.getEntry(rname);
+        }
+        Assert.assertEquals(ze2.getName(), rname);
+        Assert.assertNotEquals(ze1.getName(), ze2.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarHttpProperties.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test the System properties for JarFile that support multi-release jar files
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=0 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=100 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarHttpProperties
+ */
+
+import com.sun.net.httpserver.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class MultiReleaseJarHttpProperties extends MultiReleaseJarProperties {
+    private SimpleHttpServer server;
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        server = new SimpleHttpServer();
+        server.start();
+        super.initialize();
+    }
+
+    @Override
+    protected void initializeClassLoader() throws Exception {
+        URL[] urls = new URL[]{
+                new URL("http://localhost:" + server.getPort() + "/multi-release-jar")
+        };
+        cldr = new URLClassLoader(urls);
+        // load any class, Main is convenient and in the root entries
+        rootClass = cldr.loadClass("version.Main");
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        // Windows requires server to stop before file is deleted
+        if (server != null)
+            server.stop();
+        super.close();
+    }
+
+    /*
+     * jdk.util.jar.enableMultiRelease=force is a no-op for URLClassLoader
+     */
+
+    @Test
+    public void testURLClassLoader() throws Throwable {
+        Class<?> vcls = cldr.loadClass("version.Version");
+        invokeMethod(vcls, rtVersion);
+    }
+
+    @Test
+    public void testGetResourceAsStream() throws Exception {
+        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
+        // use rootClass as a base for getting resources
+        getResourceAsStream(rootClass, resource);
+    }
+
+    @Test
+    public void testGetResource() throws Exception {
+        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
+        // use rootClass as a base for getting resources
+        getResource(rootClass, resource);
+    }
+}
+
+/**
+ * Extremely simple server that only performs one task.  The server listens for
+ * requests on the ephemeral port.  If it sees a request that begins with
+ * "/multi-release-jar", it consumes the request and returns a stream of bytes
+ * representing the jar file multi-release.jar found in "userdir".
+ */
+class SimpleHttpServer {
+    private static final String userdir = System.getProperty("user.dir", ".");
+    private static final Path multirelease = Paths.get(userdir, "multi-release.jar");
+
+    private final HttpServer server;
+
+    public SimpleHttpServer() throws IOException {
+        server = HttpServer.create();
+    }
+
+    public void start() throws IOException {
+        server.bind(new InetSocketAddress(0), 0);
+        server.createContext("/multi-release-jar", t -> {
+            try (InputStream is = t.getRequestBody()) {
+                is.readAllBytes();  // probably not necessary to consume request
+                byte[] bytes = Files.readAllBytes(multirelease);
+                t.sendResponseHeaders(200, bytes.length);
+                try (OutputStream os = t.getResponseBody()) {
+                    os.write(bytes);
+                }
+            }
+        });
+        server.setExecutor(null); // creates a default executor
+        server.start();
+    }
+
+    public void stop() {
+        server.stop(0);
+    }
+
+    int getPort() {
+        return server.getAddress().getPort();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarIterators.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @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 static java.util.jar.JarFile.Release;
+import static sun.misc.Version.jdkMajorVersion;  // fixme JEP 223 Version
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+public class MultiReleaseJarIterators {
+    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, Release.BASE)) {
+            testEnumeration(jf, baseEntries);
+            testStream(jf, baseEntries);
+        }
+
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+            testEnumeration(jf, v9Entries);
+            testStream(jf, v9Entries);
+        }
+
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+            Map<String,JarEntry> expectedEntries;
+            switch (jdkMajorVersion()) {
+                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, Release.BASE)) {
+            testEnumeration(jf, uvEntries);
+            testStream(jf, uvEntries);
+        }
+
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+            testEnumeration(jf, uvEntries);
+            testStream(jf, uvEntries);
+        }
+
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+            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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarProperties.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test the System properties for JarFile that support multi-release jar files
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=0 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=100 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import static sun.misc.Version.jdkMajorVersion;  // fixme JEP 223 Version
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class MultiReleaseJarProperties {
+    final static int ROOTVERSION = 8; // magic number from knowledge of internals
+    final static String userdir = System.getProperty("user.dir", ".");
+    final static File multirelease = new File(userdir, "multi-release.jar");
+    protected int rtVersion;
+    boolean force;
+    protected ClassLoader cldr;
+    protected Class<?> rootClass;
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildMultiReleaseJar();
+
+        rtVersion = Integer.getInteger("jdk.util.jar.version", jdkMajorVersion());
+        String mrprop = System.getProperty("jdk.util.jar.enableMultiRelease", "");
+        if (mrprop.equals("false")) {
+            rtVersion = ROOTVERSION;
+        } else if (rtVersion < ROOTVERSION) {
+            rtVersion = ROOTVERSION;
+        } else if (rtVersion > jdkMajorVersion()) {
+            rtVersion = jdkMajorVersion();
+        }
+        force = mrprop.equals("force");
+
+        initializeClassLoader();
+    }
+
+    protected void initializeClassLoader() throws Exception {
+        URL[] urls = new URL[]{multirelease.toURI().toURL()};
+        cldr = new URLClassLoader(urls);
+        // load any class, Main is convenient and in the root entries
+        rootClass = cldr.loadClass("version.Main");
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        ((URLClassLoader)cldr).close();
+        Files.delete(multirelease.toPath());
+    }
+
+    /*
+     * jdk.util.jar.enableMultiRelease=force is a no-op for URLClassLoader
+     */
+    @Test
+    public void testURLClassLoader() throws Throwable {
+        Class<?> vcls = cldr.loadClass("version.Version");
+        invokeMethod(vcls, rtVersion);
+    }
+
+    protected void invokeMethod(Class<?> vcls, int expected) throws Throwable {
+        MethodType mt = MethodType.methodType(int.class);
+        MethodHandle mh = MethodHandles.lookup().findVirtual(vcls, "getVersion", mt);
+        Assert.assertEquals(expected, (int) mh.invoke(vcls.newInstance()));
+    }
+
+    /*
+     * jdk.util.jar.enableMultiRelease=force should affect a custom class loader
+     */
+    @Test
+    public void testClassLoader() throws Throwable {
+        try (JarFile jf = new JarFile(multirelease)) {  // do not set runtime versioning
+            ClassLoader cldr = new CustomClassLoader(jf);
+            Class<?> vcls = cldr.loadClass("version.Version");
+            if (rtVersion == 9) {
+                try {
+                    cldr.loadClass("version.PackagePrivate");
+                } catch (ClassNotFoundException x) {
+                    if (force) throw x;
+                }
+            }
+            invokeMethod(vcls, force ? rtVersion : ROOTVERSION);
+        }
+    }
+
+    private static class CustomClassLoader extends ClassLoader {
+        private final JarFile jf;
+
+        CustomClassLoader(JarFile jf) throws Exception {
+            super(null);
+            this.jf = jf;
+        }
+
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            try {
+                byte[] b;
+                String entryName = name.replace(".", "/") + ".class";
+                JarEntry je = jf.getJarEntry(entryName);
+                if (je != null) {
+                    try (InputStream is = jf.getInputStream(je)) {
+                        b = new byte[(int) je.getSize()];
+                        is.read(b);
+                    }
+                    return defineClass(name, b, 0, b.length);
+                }
+                throw new ClassNotFoundException(name);
+            } catch (IOException x) {
+                throw new ClassNotFoundException(x.getMessage());
+            }
+        }
+    }
+
+    @Test
+    public void testGetResourceAsStream() throws Exception {
+        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
+        // use fileRootClass as a base for getting resources
+        getResourceAsStream(rootClass, resource);
+    }
+
+    protected void getResourceAsStream(Class<?> rootClass, String resource) throws Exception {
+        try (InputStream is = rootClass.getResourceAsStream(resource)) {
+            byte[] bytes = is.readAllBytes();
+            resource = new String(bytes);
+        }
+        String match = "return " + rtVersion + ";";
+        Assert.assertTrue(resource.contains(match));
+    }
+
+    @Test
+    public void testGetResource() throws Exception {
+        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
+        // use rootClass as a base for getting resources
+        getResource(rootClass, resource);
+    }
+
+    protected void getResource(Class<?> rootClass, String resource) throws Exception {
+        URL url = rootClass.getResource(resource);
+        try (InputStream is = url.openStream()) {
+            byte[] bytes = is.readAllBytes();
+            resource = new String(bytes);
+        }
+        String match = "return " + rtVersion + ";";
+        Assert.assertTrue(resource.contains(match));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarSecurity.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test potential security related issues
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarSecurity
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.security.CodeSigner;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+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 MultiReleaseJarSecurity {
+    String userdir = System.getProperty("user.dir",".");
+    File multirelease = new File(userdir, "multi-release.jar");
+    File signedmultirelease = new File(userdir, "signed-multi-release.jar");
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildMultiReleaseJar();
+        creator.buildSignedMultiReleaseJar();
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        Files.delete(multirelease.toPath());
+        Files.delete(signedmultirelease.toPath());
+    }
+
+    @Test
+    public void testCertsAndSigners() throws IOException {
+        try (JarFile jf = new JarFile(signedmultirelease, true, ZipFile.OPEN_READ, JarFile.Release.RUNTIME)) {
+            int version = sun.misc.Version.jdkMajorVersion();  // fixme JEP 223 Version
+            CertsAndSigners vcas = new CertsAndSigners(jf, jf.getJarEntry("version/Version.class"));
+            CertsAndSigners rcas = new CertsAndSigners(jf, jf.getJarEntry("META-INF/versions/" + version + "/version/Version.class"));
+            Assert.assertTrue(Arrays.equals(rcas.getCertificates(), vcas.getCertificates()));
+            Assert.assertTrue(Arrays.equals(rcas.getCodeSigners(), vcas.getCodeSigners()));
+        }
+    }
+
+    private static class CertsAndSigners {
+        final private JarFile jf;
+        final private JarEntry je;
+        private boolean readComplete;
+
+        CertsAndSigners(JarFile jf, JarEntry je) {
+            this.jf = jf;
+            this.je = je;
+        }
+
+        Certificate[] getCertificates() throws IOException {
+            readEntry();
+            return je.getCertificates();
+        }
+
+        CodeSigner[] getCodeSigners() throws IOException {
+            readEntry();
+            return je.getCodeSigners();
+        }
+
+        private void readEntry() throws IOException {
+            if (!readComplete) {
+                try (InputStream is = jf.getInputStream(je)) {
+                    is.readAllBytes();
+                }
+                readComplete = true;
+            }
+        }
+    }
+}
--- a/jdk/test/java/util/logging/LogManagerAppContextDeadlock.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/java/util/logging/LogManagerAppContextDeadlock.java	Wed Jul 05 21:24:14 2017 +0200
@@ -141,6 +141,7 @@
         t1.setDaemon(true);
         t1.start();
         Thread t2 = new Thread() {
+            public Object logger;
             public void run() {
                 sem3.release();
                 try {
@@ -151,7 +152,10 @@
                     Thread.interrupted();
                 }
                 System.out.println("Logger.getLogger(name).info(name)");
-                Logger.getLogger(test.name());//.info(name);
+                // stick the logger in an instance variable to prevent it
+                // from being garbage collected before the main thread
+                // calls LogManager.getLogger() below.
+                logger = Logger.getLogger(test.name());//.info(name);
                 System.out.println("Done: Logger.getLogger(name).info(name)");
             }
         };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/crypto/JceSecurity/FinalRestricted.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * 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 8149417
+ * @summary Use final restricted flag
+ */
+
+import java.security.*;
+import java.lang.reflect.*;
+
+public class FinalRestricted {
+
+    public static void main(String[] args) throws Exception {
+
+        int modifiers = Class.forName("javax.crypto.JceSecurity")
+                    .getDeclaredField("isRestricted").getModifiers();
+        if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers) &&
+                Modifier.isPrivate(modifiers))) {
+            throw new Exception("JceSecurity.isRestricted is not " +
+                                "a private static final field!");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/Stapling/StapleEnableProps.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,721 @@
+/*
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8145854
+ * @summary SSLContextImpl.statusResponseManager should be generated if required
+ * @library ../../../../java/security/testlibrary
+ * @build CertificateBuilder SimpleOCSPServer
+ * @run main/othervm StapleEnableProps
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.math.BigInteger;
+import java.security.*;
+import java.nio.*;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import sun.security.testlibrary.SimpleOCSPServer;
+import sun.security.testlibrary.CertificateBuilder;
+
+public class StapleEnableProps {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = false;
+
+    // These two ByteBuffer references will be used to hang onto ClientHello
+    // messages with and without the status_request[_v2] extensions.  These
+    // will be used in the server-side stapling tests.
+    private static ByteBuffer cHelloStaple;
+    private static ByteBuffer cHelloNoStaple;
+
+    // The following items are used to set up the keystores.
+    private static final String passwd = "passphrase";
+    private static final String ROOT_ALIAS = "root";
+    private static final String INT_ALIAS = "intermediate";
+    private static final String SSL_ALIAS = "ssl";
+
+    // PKI components we will need for this test
+    private static KeyManagerFactory kmf;
+    private static TrustManagerFactory tmf;
+    private static KeyStore rootKeystore;       // Root CA Keystore
+    private static KeyStore intKeystore;        // Intermediate CA Keystore
+    private static KeyStore serverKeystore;     // SSL Server Keystore
+    private static KeyStore trustStore;         // SSL Client trust store
+    private static SimpleOCSPServer rootOcsp;   // Root CA OCSP Responder
+    private static int rootOcspPort;            // Port for root OCSP
+    private static SimpleOCSPServer intOcsp;    // Intermediate CA OCSP server
+    private static int intOcspPort;             // Port for intermediate OCSP
+
+    // A few helpful TLS definitions to make it easier
+    private static final int HELLO_EXT_STATUS_REQ = 5;
+    private static final int HELLO_EXT_STATUS_REQ_V2 = 17;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "ssl");
+        }
+
+        // Create the PKI we will use for the test and start the OCSP servers
+        createPKI();
+
+        // Set up the KeyManagerFactory and TrustManagerFactory
+        kmf = KeyManagerFactory.getInstance("PKIX");
+        kmf.init(serverKeystore, passwd.toCharArray());
+        tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(trustStore);
+
+        // Run the client and server property tests
+        testClientProp();
+        testServerProp();
+
+    }
+
+    private static void testClientProp() throws Exception {
+        SSLEngineResult clientResult;
+
+        // Test with the client-side enable property set to true
+        System.out.println("=========================================");
+        System.out.println("Client Test 1: " +
+                "jdk.tls.client.enableStatusRequestExtension = true");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "true");
+        SSLContext ctxStaple = SSLContext.getInstance("TLS");
+        ctxStaple.init(null, tmf.getTrustManagers(), null);
+        SSLEngine engine = ctxStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        SSLSession session = engine.getSession();
+        ByteBuffer clientOut = ByteBuffer.wrap("I'm a Client".getBytes());
+        ByteBuffer cTOs =
+                ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, true, true);
+        cHelloStaple = cTOs;
+
+        // Test with the property set to false
+        System.out.println("=========================================");
+        System.out.println("Client Test 2: " +
+                "jdk.tls.client.enableStatusRequestExtension = false");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "false");
+        SSLContext ctxNoStaple = SSLContext.getInstance("TLS");
+        ctxNoStaple.init(null, tmf.getTrustManagers(), null);
+        engine = ctxNoStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        session = engine.getSession();
+        cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, false, false);
+        cHelloNoStaple = cTOs;
+    }
+
+    private static void testServerProp() throws Exception {
+        SSLEngineResult serverResult;
+        HandshakeStatus hsStat;
+
+        // Test with the server-side enable property set to true
+        System.out.println("=========================================");
+        System.out.println("Server Test 1: " +
+                "jdk.tls.server.enableStatusRequestExtension = true");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                "true");
+        SSLContext ctxStaple = SSLContext.getInstance("TLS");
+        ctxStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        SSLEngine engine = ctxStaple.createSSLEngine();
+        engine.setUseClientMode(false);
+        SSLSession session = engine.getSession();
+        ByteBuffer serverOut = ByteBuffer.wrap("I'm a Server".getBytes());
+        ByteBuffer serverIn =
+                ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
+        ByteBuffer sTOc =
+                ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Consume the client hello
+        serverResult = engine.unwrap(cHelloStaple, serverIn);
+        log("server unwrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Server unwrap got status: " +
+                    serverResult.getStatus());
+        } else if (serverResult.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
+             throw new SSLException("Server unwrap expected NEED_TASK, got: " +
+                    serverResult.getHandshakeStatus());
+        }
+        runDelegatedTasks(serverResult, engine);
+        if (engine.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+            throw new SSLException("Expected NEED_WRAP, got: " +
+                    engine.getHandshakeStatus());
+        }
+
+        // Generate a TLS record with the ServerHello
+        serverResult = engine.wrap(serverOut, sTOc);
+        log("client wrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    serverResult.getStatus());
+        }
+        sTOc.flip();
+        System.out.println(dumpHexBytes(sTOc));
+        checkServerHello(sTOc, false, true);
+
+        // Flip the client hello so we can reuse it in the next test.
+        cHelloStaple.flip();
+
+        // Test with the server-side enable property set to false
+        System.out.println("=========================================");
+        System.out.println("Server Test 2: " +
+                "jdk.tls.server.enableStatusRequestExtension = false");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                "false");
+        SSLContext ctxNoStaple = SSLContext.getInstance("TLS");
+        ctxNoStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        engine = ctxNoStaple.createSSLEngine();
+        engine.setUseClientMode(false);
+        session = engine.getSession();
+        serverIn = ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
+        sTOc = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Consume the client hello
+        serverResult = engine.unwrap(cHelloStaple, serverIn);
+        log("server unwrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Server unwrap got status: " +
+                    serverResult.getStatus());
+        } else if (serverResult.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
+             throw new SSLException("Server unwrap expected NEED_TASK, got: " +
+                    serverResult.getHandshakeStatus());
+        }
+        runDelegatedTasks(serverResult, engine);
+        if (engine.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+            throw new SSLException("Expected NEED_WRAP, got: " +
+                    engine.getHandshakeStatus());
+        }
+
+        // Generate a TLS record with the ServerHello
+        serverResult = engine.wrap(serverOut, sTOc);
+        log("client wrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    serverResult.getStatus());
+        }
+        sTOc.flip();
+        System.out.println(dumpHexBytes(sTOc));
+        checkServerHello(sTOc, false, false);
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() +
+            " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+
+    /**
+     * Dump a ByteBuffer as a hexdump to stdout.  The dumping routine will
+     * start at the current position of the buffer and run to its limit.
+     * After completing the dump, the position will be returned to its
+     * starting point.
+     *
+     * @param data the ByteBuffer to dump to stdout.
+     *
+     * @return the hexdump of the byte array.
+     */
+    private static String dumpHexBytes(ByteBuffer data) {
+        StringBuilder sb = new StringBuilder();
+        if (data != null) {
+            int i = 0;
+            data.mark();
+            while (data.hasRemaining()) {
+                if (i % 16 == 0 && i != 0) {
+                    sb.append("\n");
+                }
+                sb.append(String.format("%02X ", data.get()));
+                i++;
+            }
+            data.reset();
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Tests the ClientHello for the presence (or not) of the status_request
+     * and status_request_v2 hello extensions.  It is assumed that the provided
+     * ByteBuffer has its position set at the first byte of the TLS record
+     * containing the ClientHello and contains the entire hello message.  Upon
+     * successful completion of this method the ByteBuffer will have its
+     * position reset to the initial offset in the buffer.  If an exception is
+     * thrown the position at the time of the exception will be preserved.
+     *
+     * @param data the ByteBuffer containing the ClientHello bytes
+     * @param statReqPresent true if the status_request hello extension should
+     * be present.
+     * @param statReqV2Present true if the status_request_v2 hello extension
+     * should be present.
+     *
+     * @throws SSLException if the presence or lack of either the
+     * status_request or status_request_v2 extensions is inconsistent with
+     * the expected settings in the statReqPresent or statReqV2Present
+     * parameters.
+     */
+    private static void checkClientHello(ByteBuffer data,
+            boolean statReqPresent, boolean statReqV2Present)
+            throws SSLException {
+        boolean hasV1 = false;
+        boolean hasV2 = false;
+        Objects.requireNonNull(data);
+        data.mark();
+
+        // Process the TLS record header
+        int type = Byte.toUnsignedInt(data.get());
+        int ver_major = Byte.toUnsignedInt(data.get());
+        int ver_minor = Byte.toUnsignedInt(data.get());
+        int recLen = Short.toUnsignedInt(data.getShort());
+
+        // Simple sanity checks
+        if (type != 22) {
+            throw new SSLException("Not a handshake: Type = " + type);
+        } else if (recLen > data.remaining()) {
+            throw new SSLException("Incomplete record in buffer: " +
+                    "Record length = " + recLen + ", Remaining = " +
+                    data.remaining());
+        }
+
+        // Grab the handshake message header.
+        int msgHdr = data.getInt();
+        int msgType = (msgHdr >> 24) & 0x000000FF;
+        int msgLen = msgHdr & 0x00FFFFFF;
+
+        // More simple sanity checks
+        if (msgType != 1) {
+            throw new SSLException("Not a ClientHello: Type = " + msgType);
+        }
+
+        // Skip over the protocol version and client random
+        data.position(data.position() + 34);
+
+        // Jump past the session ID (if there is one)
+        int sessLen = Byte.toUnsignedInt(data.get());
+        if (sessLen != 0) {
+            data.position(data.position() + sessLen);
+        }
+
+        // Jump past the cipher suites
+        int csLen = Short.toUnsignedInt(data.getShort());
+        if (csLen != 0) {
+            data.position(data.position() + csLen);
+        }
+
+        // ...and the compression
+        int compLen = Byte.toUnsignedInt(data.get());
+        if (compLen != 0) {
+            data.position(data.position() + compLen);
+        }
+
+        // Now for the fun part.  Go through the extensions and look
+        // for the two status request exts.
+        int extsLen = Short.toUnsignedInt(data.getShort());
+        while (data.hasRemaining()) {
+            int extType = Short.toUnsignedInt(data.getShort());
+            int extLen = Short.toUnsignedInt(data.getShort());
+            hasV1 |= (extType == HELLO_EXT_STATUS_REQ);
+            hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);
+            data.position(data.position() + extLen);
+        }
+
+        if (hasV1 != statReqPresent) {
+            throw new SSLException("The status_request extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqPresent + ", actual = " + hasV1);
+        } else if (hasV2 != statReqV2Present) {
+            throw new SSLException("The status_request_v2 extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqV2Present + ", actual = " + hasV2);
+        }
+
+        // We should be at the end of the ClientHello
+        data.reset();
+    }
+
+    /**
+     * Tests the ServerHello for the presence (or not) of the status_request
+     * or status_request_v2 hello extension.  It is assumed that the provided
+     * ByteBuffer has its position set at the first byte of the TLS record
+     * containing the ServerHello and contains the entire hello message.  Upon
+     * successful completion of this method the ByteBuffer will have its
+     * position reset to the initial offset in the buffer.  If an exception is
+     * thrown the position at the time of the exception will be preserved.
+     *
+     * @param statReqPresent true if the status_request hello extension should
+     * be present.
+     * @param statReqV2Present true if the status_request_v2 hello extension
+     * should be present.
+     *
+     * @throws SSLException if the presence or lack of either the
+     * status_request or status_request_v2 extensions is inconsistent with
+     * the expected settings in the statReqPresent or statReqV2Present
+     * parameters.
+     */
+    private static void checkServerHello(ByteBuffer data,
+            boolean statReqPresent, boolean statReqV2Present)
+            throws SSLException {
+        boolean hasV1 = false;
+        boolean hasV2 = false;
+        Objects.requireNonNull(data);
+        int startPos = data.position();
+        data.mark();
+
+        // Process the TLS record header
+        int type = Byte.toUnsignedInt(data.get());
+        int ver_major = Byte.toUnsignedInt(data.get());
+        int ver_minor = Byte.toUnsignedInt(data.get());
+        int recLen = Short.toUnsignedInt(data.getShort());
+
+        // Simple sanity checks
+        if (type != 22) {
+            throw new SSLException("Not a handshake: Type = " + type);
+        } else if (recLen > data.remaining()) {
+            throw new SSLException("Incomplete record in buffer: " +
+                    "Record length = " + recLen + ", Remaining = " +
+                    data.remaining());
+        }
+
+        // Grab the handshake message header.
+        int msgHdr = data.getInt();
+        int msgType = (msgHdr >> 24) & 0x000000FF;
+        int msgLen = msgHdr & 0x00FFFFFF;
+
+        // More simple sanity checks
+        if (msgType != 2) {
+            throw new SSLException("Not a ServerHello: Type = " + msgType);
+        }
+
+        // Skip over the protocol version and server random
+        data.position(data.position() + 34);
+
+        // Jump past the session ID
+        int sessLen = Byte.toUnsignedInt(data.get());
+        if (sessLen != 0) {
+            data.position(data.position() + sessLen);
+        }
+
+        // Skip the cipher suite and compression method
+        data.position(data.position() + 3);
+
+        // Go through the extensions and look for the request extension
+        // expected by the caller.
+        int extsLen = Short.toUnsignedInt(data.getShort());
+        while (data.position() < recLen + startPos + 5) {
+            int extType = Short.toUnsignedInt(data.getShort());
+            int extLen = Short.toUnsignedInt(data.getShort());
+            hasV1 |= (extType == HELLO_EXT_STATUS_REQ);
+            hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);
+            data.position(data.position() + extLen);
+        }
+
+        if (hasV1 != statReqPresent) {
+            throw new SSLException("The status_request extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqPresent + ", actual = " + hasV1);
+        } else if (hasV2 != statReqV2Present) {
+            throw new SSLException("The status_request_v2 extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqV2Present + ", actual = " + hasV2);
+        }
+
+        // Reset the position to the initial spot at the start of this method.
+        data.reset();
+    }
+
+    /**
+     * Creates the PKI components necessary for this test, including
+     * Root CA, Intermediate CA and SSL server certificates, the keystores
+     * for each entity, a client trust store, and starts the OCSP responders.
+     */
+    private static void createPKI() throws Exception {
+        CertificateBuilder cbld = new CertificateBuilder();
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyStore.Builder keyStoreBuilder =
+                KeyStore.Builder.newInstance("PKCS12", null,
+                        new KeyStore.PasswordProtection(passwd.toCharArray()));
+
+        // Generate Root, IntCA, EE keys
+        KeyPair rootCaKP = keyGen.genKeyPair();
+        log("Generated Root CA KeyPair");
+        KeyPair intCaKP = keyGen.genKeyPair();
+        log("Generated Intermediate CA KeyPair");
+        KeyPair sslKP = keyGen.genKeyPair();
+        log("Generated SSL Cert KeyPair");
+
+        // Set up the Root CA Cert
+        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
+        cbld.setPublicKey(rootCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("1"));
+        // Make a 3 year validity starting from 60 days ago
+        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+        long end = start + TimeUnit.DAYS.toMillis(1085);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        // Make our Root CA Cert!
+        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Root CA Created:\n" + certInfo(rootCert));
+
+        // Now build a keystore and add the keys and cert
+        rootKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] rootChain = {rootCert};
+        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
+                passwd.toCharArray(), rootChain);
+
+        // Now fire up the OCSP responder
+        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
+        rootOcsp.enableLog(logging);
+        rootOcsp.setNextUpdateInterval(3600);
+        rootOcsp.start();
+        Thread.sleep(1000);         // Give the server a second to start up
+        rootOcspPort = rootOcsp.getPort();
+        String rootRespURI = "http://localhost:" + rootOcspPort;
+        log("Root OCSP Responder URI is " + rootRespURI);
+
+        // Now that we have the root keystore and OCSP responder we can
+        // create our intermediate CA.
+        cbld.reset();
+        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
+        cbld.setPublicKey(intCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("100"));
+        // Make a 2 year validity starting from 30 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
+        end = start + TimeUnit.DAYS.toMillis(730);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        cbld.addAIAExt(Collections.singletonList(rootRespURI));
+        // Make our Intermediate CA Cert!
+        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Intermediate CA Created:\n" + certInfo(intCaCert));
+
+        // Provide intermediate CA cert revocation info to the Root CA
+        // OCSP responder.
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(intCaCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        intKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] intChain = {intCaCert, rootCert};
+        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
+                passwd.toCharArray(), intChain);
+        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // Now fire up the Intermediate CA OCSP responder
+        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
+                INT_ALIAS, null);
+        intOcsp.enableLog(logging);
+        intOcsp.setNextUpdateInterval(3600);
+        intOcsp.start();
+        Thread.sleep(1000);
+        intOcspPort = intOcsp.getPort();
+        String intCaRespURI = "http://localhost:" + intOcspPort;
+        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
+
+        // Last but not least, let's make our SSLCert and add it to its own
+        // Keystore
+        cbld.reset();
+        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
+        cbld.setPublicKey(sslKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("4096"));
+        // Make a 1 year validity starting from 7 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+        end = start + TimeUnit.DAYS.toMillis(365);
+        cbld.setValidity(new Date(start), new Date(end));
+
+        // Add extensions
+        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
+        boolean[] kuBits = {true, false, true, false, false, false,
+            false, false, false};
+        cbld.addKeyUsageExt(kuBits);
+        List<String> ekuOids = new ArrayList<>();
+        ekuOids.add("1.3.6.1.5.5.7.3.1");
+        ekuOids.add("1.3.6.1.5.5.7.3.2");
+        cbld.addExtendedKeyUsageExt(ekuOids);
+        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
+        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
+        // Make our SSL Server Cert!
+        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("SSL Certificate Created:\n" + certInfo(sslCert));
+
+        // Provide SSL server cert revocation info to the Intermeidate CA
+        // OCSP responder.
+        revInfo = new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        serverKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert};
+        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
+                passwd.toCharArray(), sslChain);
+        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // And finally a Trust Store for the client
+        trustStore = keyStoreBuilder.getKeyStore();
+        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
+    }
+
+    private static void addCommonExts(CertificateBuilder cbld,
+            PublicKey subjKey, PublicKey authKey) throws IOException {
+        cbld.addSubjectKeyIdExt(subjKey);
+        cbld.addAuthorityKeyIdExt(authKey);
+    }
+
+    private static void addCommonCAExts(CertificateBuilder cbld)
+            throws IOException {
+        cbld.addBasicConstraintsExt(true, true, -1);
+        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
+        boolean[] kuBitSettings = {true, false, false, false, false, true,
+            true, false, false};
+        cbld.addKeyUsageExt(kuBitSettings);
+    }
+
+    /**
+     * Helper routine that dumps only a few cert fields rather than
+     * the whole toString() output.
+     *
+     * @param cert an X509Certificate to be displayed
+     *
+     * @return the String output of the issuer, subject and
+     * serial number
+     */
+    private static String certInfo(X509Certificate cert) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
+                append("\n");
+        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,711 @@
+/*
+ * 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 jdk.internal.misc.Unsafe;
+import java.lang.reflect.Field;
+
+/*
+ * @test
+ * @summary Test Unsafe.copySwapMemory
+ * @modules java.base/jdk.internal.misc
+ */
+public class CopySwap {
+    private static final boolean DEBUG = Boolean.getBoolean("CopySwap.DEBUG");
+
+    public static final long KB = 1024;
+    public static final long MB = KB * 1024;
+    public static final long GB = MB * 1024;
+
+    private static final Unsafe UNSAFE;
+    private static final int SMALL_COPY_SIZE = 32;
+    private static final int BASE_ALIGNMENT = 16;
+
+    static {
+        try {
+            Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe");
+            f.setAccessible(true);
+            UNSAFE = (jdk.internal.misc.Unsafe) f.get(null);
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to get Unsafe instance.", e);
+        }
+    }
+
+    private static long alignDown(long value, long alignment) {
+        return value & ~(alignment - 1);
+    }
+
+    private static long alignUp(long value, long alignment) {
+        return (value + alignment - 1) & ~(alignment - 1);
+    }
+
+    private static boolean isAligned(long value, long alignment) {
+        return value == alignDown(value, alignment);
+    }
+
+    private CopySwap() {
+    }
+
+    /**
+     * Generate verification data for a given offset
+     *
+     * The verification data is used to verify that the correct bytes
+     * have indeed been copied and byte swapped.
+     *
+     * The data is generated based on the offset (in bytes) into the
+     * source buffer. For a native buffer the offset is relative to
+     * the base pointer. For a heap array it is relative to the
+     * address of the first array element.
+     *
+     * This method will return the result of doing an elementSize byte
+     * read starting at offset (in bytes).
+     *
+     * @param offset offset into buffer
+     * @param elemSize size (in bytes) of the element
+     *
+     * @return the verification data, only the least significant
+     * elemSize*8 bits are set, zero extended
+     */
+    private long getVerificationDataForOffset(long offset, long elemSize) {
+        byte[] bytes = new byte[(int)elemSize];
+
+        for (long i = 0; i < elemSize; i++) {
+            bytes[(int)i] = (byte)(offset + i);
+        }
+
+        long o = UNSAFE.arrayBaseOffset(byte[].class);
+
+        switch ((int)elemSize) {
+        case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o));
+        case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o));
+        case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o));
+        case 8: return UNSAFE.getLongUnaligned(bytes, o);
+        default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+        }
+    }
+
+    /**
+     * Verify byte swapped data
+     *
+     * @param ptr the data to verify
+     * @param srcOffset the srcOffset (in bytes) from which the copy started,
+     *        used as key to regenerate the verification data
+     * @param dstOffset the offset (in bytes) in the array at which to start
+     *        the verification, relative to the first element in the array
+     * @param size size (in bytes) of data to to verify
+     * @param elemSize size (in bytes) of the individual array elements
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) {
+        for (long offset = 0; offset < size; offset += elemSize) {
+            long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize);
+            long expected = byteSwap(expectedUnswapped, elemSize);
+
+            long actual = getArrayElem(ptr, dstOffset + offset, elemSize);
+
+            if (expected != actual) {
+                throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) +
+                                           " dstOffset: 0x" + Long.toHexString(dstOffset) +
+                                           " size: 0x" + Long.toHexString(size) +
+                                           " offset: 0x" + Long.toHexString(offset) +
+                                           " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) +
+                                           " expected: 0x" + Long.toHexString(expected) +
+                                           " != actual: 0x" + Long.toHexString(actual));
+            }
+        }
+    }
+
+    /**
+     * Initialize an array with verification friendly data
+     *
+     * @param ptr pointer to the data to initialize
+     * @param size size (in bytes) of the data
+     * @param elemSize size (in bytes) of the individual elements
+     */
+    private void initVerificationData(GenericPointer ptr, long size, long elemSize) {
+        for (long offset = 0; offset < size; offset++) {
+            byte data = (byte)getVerificationDataForOffset(offset, 1);
+
+            if (ptr.isOnHeap()) {
+                UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data);
+            } else {
+                UNSAFE.putByte(ptr.getOffset() + offset, data);
+            }
+        }
+    }
+
+    /**
+     * Allocate a primitive array
+     *
+     * @param size size (in bytes) of all the array elements (elemSize * length)
+     * @param elemSize the size of the array elements
+     *
+     * @return a newly allocated primitive array
+     */
+    Object allocArray(long size, long elemSize) {
+        int length = (int)(size / elemSize);
+
+        switch ((int)elemSize) {
+        case 2: return new short[length];
+        case 4: return new int[length];
+        case 8: return new long[length];
+        default:
+            throw new IllegalArgumentException("Invalid element size: " + elemSize);
+        }
+    }
+
+    /**
+     * Get the value of a primitive array entry
+     *
+     * @param ptr pointer to the data
+     * @param offset offset (in bytes) of the array element, relative to the first element in the array
+     *
+     * @return the array element, as an unsigned long
+     */
+    private long getArrayElem(GenericPointer ptr, long offset, long elemSize) {
+        if (ptr.isOnHeap()) {
+            Object o = ptr.getObject();
+            int index = (int)(offset / elemSize);
+
+            if (o instanceof short[]) {
+                short[] arr = (short[])o;
+                return Short.toUnsignedLong(arr[index]);
+            } else if (o instanceof int[]) {
+                int[] arr = (int[])o;
+                return Integer.toUnsignedLong(arr[index]);
+            } else if (o instanceof long[]) {
+                long[] arr = (long[])o;
+                return arr[index];
+            } else {
+                throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName());
+            }
+        } else {
+            long addr = ptr.getOffset() + offset;
+
+            switch ((int)elemSize) {
+            case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr));
+            case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr));
+            case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr));
+            case 8: return UNSAFE.getLongUnaligned(null, addr);
+            default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+            }
+        }
+    }
+
+    private void putValue(long addr, long elemSize, long value) {
+        switch ((int)elemSize) {
+        case 1: UNSAFE.putByte(addr, (byte)value); break;
+        case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break;
+        case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break;
+        case 8: UNSAFE.putLongUnaligned(null, addr, value); break;
+        default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+        }
+    }
+
+    /**
+     * Get the size of the elements for an array
+     *
+     * @param o a primitive heap array
+     *
+     * @return the size (in bytes) of the individual array elements
+     */
+    private long getArrayElemSize(Object o) {
+        if (o instanceof short[]) {
+            return 2;
+        } else if (o instanceof int[]) {
+            return 4;
+        } else if (o instanceof long[]) {
+            return 8;
+        } else {
+            throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName());
+        }
+    }
+
+    /**
+     * Byte swap a value
+     *
+     * @param value the value to swap, only the bytes*8 least significant bits are used
+     * @param size size (in bytes) of the value
+     *
+     * @return the byte swapped value in the bytes*8 least significant bits
+     */
+    private long byteSwap(long value, long size) {
+        switch ((int)size) {
+        case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value));
+        case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value));
+        case 8: return Long.reverseBytes(value);
+        default: throw new IllegalArgumentException("Invalid element size: " + size);
+        }
+    }
+
+    /**
+     * Verify data in a heap array which has *not* been byte swapped
+     *
+     * @param ptr the data to verify
+     * @param startOffset the offset (in bytes) at which to start the verification
+     * @param size size (in bytes) of the data to verify
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void verifyUnswappedData(GenericPointer ptr, long startOffset, long size) {
+        for (long elemOffset = startOffset; elemOffset < startOffset + size; elemOffset++) {
+            byte expected = (byte)getVerificationDataForOffset(elemOffset, 1);
+
+            byte actual;
+            if (ptr.isOnHeap()) {
+                actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + elemOffset);
+            } else {
+                actual = UNSAFE.getByte(ptr.getOffset() + elemOffset);
+            }
+
+            if (expected != actual) {
+                throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) +
+                                           " size: 0x" + Long.toHexString(size) +
+                                           " elemOffset: 0x" + Long.toHexString(elemOffset) +
+                                           " expected: 0x" + Long.toHexString(expected) +
+                                           " != actual: 0x" + Long.toHexString(actual));
+            }
+        }
+    }
+
+
+    /**
+     * Copy and byte swap data from the source to the destination
+     *
+     * This method will pre-populate the whole source and destination
+     * buffers with verification friendly data. It will then use
+     * copySwapMemory to fill part of the destination buffer with
+     * swapped data from the source. Some space (padding) will be
+     * left before and after the data in the destination buffer, which
+     * should not be touched/overwritten by the copy call.
+     *
+     * Note: Both source and destination buffers will be overwritten!
+     *
+     * @param src source buffer to copy from
+     * @param srcOffset the offset (in bytes) in the source buffer, relative to
+     *        the first array element, at which to start reading data
+     * @param dst destination buffer to copy to
+     * @param dstOffset the offset (in bytes) in the destination
+     *        buffer, relative to the first array element, at which to
+     *        start writing data
+     * @param bufSize the size (in bytes) of the src and dst arrays
+     * @param copyBytes the size (in bytes) of the copy to perform,
+     *        must be a multiple of elemSize
+     * @param elemSize the size (in bytes) of the elements to byte swap
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void testCopySwap(GenericPointer src, long srcOffset,
+                              GenericPointer dst, long dstOffset,
+                              long bufSize, long copyBytes, long elemSize) {
+        if (!isAligned(copyBytes, elemSize)) {
+            throw new IllegalArgumentException(
+                "copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")");
+        }
+        if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) {
+            throw new IllegalArgumentException(
+                "srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")");
+        }
+        if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) {
+            throw new IllegalArgumentException(
+                "dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")");
+        }
+        if (srcOffset + copyBytes > bufSize) {
+            throw new IllegalArgumentException(
+                "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")");
+        }
+        if (dstOffset + copyBytes > bufSize) {
+            throw new IllegalArgumentException(
+                "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")");
+        }
+
+        // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes)
+        initVerificationData(src, bufSize, elemSize);
+        if (!src.equals(dst)) {
+            initVerificationData(dst, bufSize, elemSize);
+        }
+
+        if (DEBUG) {
+            System.out.println("===before===");
+            for (int offset = 0; offset < bufSize; offset += elemSize) {
+                long srcValue = getArrayElem(src, offset, elemSize);
+                long dstValue = getArrayElem(dst, offset, elemSize);
+
+                System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) +
+                                 " src=0x" + Long.toHexString(srcValue) +
+                                 " dst=0x" + Long.toHexString(dstValue));
+            }
+        }
+
+        // Copy & swap data into the middle of the destination buffer
+        UNSAFE.copySwapMemory(src.getObject(),
+                              src.getOffset() + srcOffset,
+                              dst.getObject(),
+                              dst.getOffset() + dstOffset,
+                              copyBytes,
+                              elemSize);
+
+        if (DEBUG) {
+            System.out.println("===after===");
+            for (int offset = 0; offset < bufSize; offset += elemSize) {
+                long srcValue = getArrayElem(src, offset, elemSize);
+                long dstValue = getArrayElem(dst, offset, elemSize);
+
+                System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) +
+                                 " src=0x" + Long.toHexString(srcValue) +
+                                 " dst=0x" + Long.toHexString(dstValue));
+            }
+        }
+
+        // Verify the the front padding is unchanged
+        verifyUnswappedData(dst, 0, dstOffset);
+
+        // Verify swapped data
+        verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize);
+
+        // Verify that the back back padding is unchanged
+        long frontAndDataBytes = dstOffset + copyBytes;
+        long trailingBytes = bufSize - frontAndDataBytes;
+        verifyUnswappedData(dst, frontAndDataBytes, trailingBytes);
+    }
+
+    /**
+     * Test various configurations copy-swapping from one buffer to the other
+     *
+     * @param src the source buffer to copy from
+     * @param dst the destination buffer to copy to
+     * @param size size (in bytes) of the buffers
+     * @param elemSize size (in bytes) of the individual elements
+     *
+     * @throws RuntimeException if an error is found
+     */
+    public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) {
+        // offset in source from which to start reading data
+        for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) {
+
+            // offset in destination at which to start writing data
+            for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) {
+
+                // number of bytes to copy
+                long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset);
+                for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) {
+                    try {
+                        testCopySwap(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize);
+                    } catch (RuntimeException e) {
+                        // Wrap the exception in another exception to catch the relevant configuration data
+                        throw new RuntimeException("testBufferPair: " +
+                                                   "src=" + src +
+                                                   " dst=" + dst +
+                                                   " elemSize=0x" + Long.toHexString(elemSize) +
+                                                   " copyBytes=0x" + Long.toHexString(copyBytes) +
+                                                   " srcOffset=0x" + Long.toHexString(srcOffset) +
+                                                   " dstOffset=0x" + Long.toHexString(dstOffset),
+                                                   e);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Test copying between various permutations of buffers
+     *
+     * @param buffers buffers to permute (src x dst)
+     * @param size size (in bytes) of buffers
+     * @param elemSize size (in bytes) of individual elements
+     *
+     * @throws RuntimeException if an error is found
+     */
+    public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) {
+        for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) {
+            for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) {
+                testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize);
+            }
+        }
+    }
+
+    /**
+     * Test copying of a specific element size
+     *
+     * @param size size (in bytes) of buffers to allocate
+     * @param elemSize size (in bytes) of individual elements
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void testElemSize(long size, long elemSize) {
+        long buf1Raw = 0;
+        long buf2Raw = 0;
+
+        try {
+            buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+            long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT);
+
+            buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+            long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT);
+
+            GenericPointer[] buffers = {
+                new GenericPointer(buf1),
+                new GenericPointer(buf2),
+                new GenericPointer(allocArray(size, elemSize)),
+                new GenericPointer(allocArray(size, elemSize))
+            };
+
+            testPermuteBuffers(buffers, size, elemSize);
+        } finally {
+            if (buf1Raw != 0) {
+                UNSAFE.freeMemory(buf1Raw);
+            }
+            if (buf2Raw != 0) {
+                UNSAFE.freeMemory(buf2Raw);
+            }
+        }
+    }
+
+    /**
+     * Verify that small copy swaps work
+     */
+    private void testSmallCopy() {
+        int smallBufSize = SMALL_COPY_SIZE;
+
+        // Test various element types and heap/native combinations
+        for (long elemSize = 2; elemSize <= 8; elemSize <<= 1) {
+            testElemSize(smallBufSize, elemSize);
+        }
+    }
+
+
+    /**
+     * Verify that large copy swaps work
+     */
+    private void testLargeCopy() {
+        long size = 2 * GB + 8;
+        long bufRaw = 0;
+
+        // Check that a large native copy succeeds
+        try {
+            try {
+                bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+            } catch (OutOfMemoryError e) {
+                // Accept failure, skip test
+                return;
+            }
+
+            long buf = alignUp(bufRaw, BASE_ALIGNMENT);
+
+            UNSAFE.copySwapMemory(null, buf, null, buf, size, 8);
+        } catch (Exception e) {
+            throw new RuntimeException("copySwapMemory of large buffer failed");
+        } finally {
+            if (bufRaw != 0) {
+                UNSAFE.freeMemory(bufRaw);
+            }
+        }
+    }
+
+    /**
+     * Run positive tests
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void testPositive() {
+        testSmallCopy();
+        testLargeCopy();
+    }
+
+    /**
+     * Run negative tests, testing corner cases and the various exceptions
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void testNegative() {
+        long bufRaw = 0;
+
+        try {
+            bufRaw = UNSAFE.allocateMemory(1024);
+            long buf = alignUp(bufRaw, BASE_ALIGNMENT);
+            short[] arr = new short[16];
+
+            // Check various illegal element sizes
+            for (int elemSize = 2; elemSize <= 8; elemSize <<= 1) {
+                long[] illegalSizes = { -1, 1, elemSize - 1, elemSize + 1, elemSize * 2 - 1 };
+                for (long size : illegalSizes) {
+                    try {
+                        // Check that illegal elemSize throws an IAE
+                        UNSAFE.copySwapMemory(null, buf, null, buf, size, elemSize);
+                        throw new RuntimeException("copySwapMemory failed to throw IAE for size=" + size + " elemSize=" + elemSize);
+                    } catch (IllegalArgumentException e) {
+                        // good
+                    }
+                }
+            }
+
+            try {
+                // Check that negative srcOffset throws an IAE
+                UNSAFE.copySwapMemory(arr, -1, arr, UNSAFE.arrayBaseOffset(arr.getClass()), 16, 2);
+                throw new RuntimeException("copySwapMemory failed to throw IAE for srcOffset=-1");
+            } catch (IllegalArgumentException e) {
+                // good
+            }
+
+            try {
+                // Check that negative dstOffset throws an IAE
+                UNSAFE.copySwapMemory(arr, UNSAFE.arrayBaseOffset(arr.getClass()), arr, -1, 16, 2);
+                throw new RuntimeException("copySwapMemory failed to throw IAE for destOffset=-1");
+            } catch (IllegalArgumentException e) {
+                // good
+            }
+
+            long illegalElemSizes[] = { 0, 1, 3, 5, 6, 7, 9, 10, -1 };
+            for (long elemSize : illegalElemSizes) {
+                try {
+                    // Check that elemSize 1 throws an IAE
+                    UNSAFE.copySwapMemory(null, buf, null, buf, 16, elemSize);
+                    throw new RuntimeException("copySwapMemory failed to throw NPE");
+                } catch (IllegalArgumentException e) {
+                    // good
+                }
+            }
+
+            try {
+                // Check that a NULL source throws NPE
+                UNSAFE.copySwapMemory(null, 0, null, buf, 16, 2);
+                throw new RuntimeException("copySwapMemory failed to throw NPE");
+            } catch (NullPointerException e) {
+                // good
+            }
+
+            try {
+                // Check that a NULL destination throws NPE
+                UNSAFE.copySwapMemory(null, buf, null, 0, 16, 2);
+                throw new RuntimeException("copySwapMemory failed to throw NPE");
+            } catch (NullPointerException e) {
+                // good
+            }
+
+            try {
+                // Check that a reference array destination throws IAE
+                UNSAFE.copySwapMemory(null, buf, new Object[16], UNSAFE.arrayBaseOffset(Object[].class), 16, 8);
+                throw new RuntimeException("copySwapMemory failed to throw NPE");
+            } catch (IllegalArgumentException e) {
+                // good
+            }
+
+            // Check that invalid source & dest pointers throw IAEs (only relevant on 32-bit platforms)
+            if (UNSAFE.addressSize() == 4) {
+                long invalidPtr = (long)1 << 35; // Pick a random bit in upper 32 bits
+
+                try {
+                    // Check that an invalid (not 32-bit clean) source pointer throws IAE
+                    UNSAFE.copySwapMemory(null, invalidPtr, null, buf, 16, 2);
+                    throw new RuntimeException("copySwapMemory failed to throw IAE for srcOffset 0x" +
+                                               Long.toHexString(invalidPtr));
+                } catch (IllegalArgumentException e) {
+                    // good
+                }
+
+                try {
+                    // Check that an invalid (not 32-bit clean) source pointer throws IAE
+                    UNSAFE.copySwapMemory(null, buf, null, invalidPtr, 16, 2);
+                    throw new RuntimeException("copySwapMemory failed to throw IAE for destOffset 0x" +
+                                               Long.toHexString(invalidPtr));
+                } catch (IllegalArgumentException e) {
+                    // good
+                }
+            }
+        } finally {
+            if (bufRaw != 0) {
+                UNSAFE.freeMemory(bufRaw);
+            }
+        }
+    }
+
+    /**
+     * Run all tests
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void test() {
+        testPositive();
+        testNegative();
+    }
+
+    public static void main(String[] args) {
+        CopySwap cs = new CopySwap();
+        cs.test();
+    }
+
+    /**
+     * Helper class to represent a "pointer" - either a heap array or
+     * a pointer to a native buffer.
+     *
+     * In the case of a native pointer, the Object is null and the offset is
+     * the absolute address of the native buffer.
+     *
+     * In the case of a heap object, the Object is a primitive array, and
+     * the offset will be set to the base offset to the first element, meaning
+     * the object and the offset together form a double-register pointer.
+     */
+    static class GenericPointer {
+        private final Object o;
+        private final long offset;
+
+        private GenericPointer(Object o, long offset) {
+            this.o = o;
+            this.offset = offset;
+        }
+
+        public String toString() {
+            return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")";
+        }
+
+        public boolean equals(Object other) {
+            if (!(other instanceof GenericPointer)) {
+                return false;
+            }
+
+            GenericPointer otherp = (GenericPointer)other;
+
+            return o == otherp.o && offset == otherp.offset;
+        }
+
+        GenericPointer(Object o) {
+            this(o, UNSAFE.arrayBaseOffset(o.getClass()));
+        }
+
+        GenericPointer(long offset) {
+            this(null, offset);
+        }
+
+        public boolean isOnHeap() {
+            return o != null;
+        }
+
+        public Object getObject() {
+            return o;
+        }
+
+        public long getOffset() {
+            return offset;
+        }
+    }
+}
--- a/jdk/test/sun/misc/SunMiscSignalTest.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/sun/misc/SunMiscSignalTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -180,6 +180,12 @@
         return newArray;
     }
 
+    // Return true if the signal is one of the shutdown signals known to the VM
+    private static boolean isShutdownSignal(Signal signal) {
+        String name = signal.getName();
+        return name.equals("INT") || name.equals("HUP") || name.equals("TERM");
+    }
+
     /**
      * Quick verification of supported signals using sun.misc.Signal.
      *
@@ -201,14 +207,24 @@
             Assert.assertEquals(signal.toString(), "SIG" + name, "toString() mismatch, ");
 
             try {
-                SignalHandler old = Signal.handle(signal, h);
+                orig = Signal.handle(signal, h);
+                printf("oldHandler: %s%n", orig);
                 Assert.assertEquals(CanRegister.YES, register, "Unexpected handle succeeded " + name);
                 try {
                     Signal.raise(signal);
                     Assert.assertEquals(CanRaise.YES, raise, "Unexpected raise success for " + name);
                     Invoked inv = h.semaphore().tryAcquire(Utils.adjustTimeout(100L),
                             TimeUnit.MILLISECONDS) ? Invoked.YES : Invoked.NO;
-                    Assert.assertEquals(inv, invoked, "handler not invoked;");
+                    if (!isShutdownSignal(signal)) {
+                        // Normal case
+                        Assert.assertEquals(inv, invoked, "handler not invoked;");
+                    } else {
+                        if (orig == SignalHandler.SIG_IGN) {
+                            Assert.assertEquals(inv, Invoked.NO, "handler should not be invoked");
+                        } else {
+                            Assert.assertEquals(inv, invoked, "handler not invoked;");
+                        }
+                    }
                 } catch (IllegalArgumentException uoe3) {
                     Assert.assertNotEquals(CanRaise.YES, raise, "raise failed for " + name +
                             ": " + uoe3.getMessage());
@@ -270,14 +286,22 @@
     }
 
     // Test expected exception when raising a signal when no handler defined
-    @Test(expectedExceptions = IllegalArgumentException.class)
+    @Test
     static void testRaiseNoConsumer() {
         Signal signal = new Signal("INT");
         SignalHandler orig = null;
         try {
-            Signal.handle(signal, SignalHandler.SIG_DFL);
+            orig = Signal.handle(signal, SignalHandler.SIG_DFL);
+            printf("oldHandler: %s%n", orig);
+            if (orig == SignalHandler.SIG_IGN) {
+                // SIG_IGN for TERM means it cannot be handled
+                return;
+            }
             Signal.raise(signal);
-        }  finally {
+            Assert.fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            printf("IAE message: %s%n", iae.getMessage());
+        } finally {
             // Restore original signal handler
             if (orig != null && signal != null) {
                 Signal.handle(signal, orig);
@@ -296,7 +320,13 @@
         }
         Handler handler = new Handler();
         Signal signal = new Signal("INT");
-        Signal.handle(signal, handler);
+        SignalHandler orig = Signal.handle(signal, handler);
+        printf("oldHandler: %s%n", orig);
+        if (orig == SignalHandler.SIG_IGN) {
+            // SIG_IGN for INT means it cannot be handled
+            return;
+        }
+
         Signal.raise(signal);
         boolean handled = handler.semaphore()
                 .tryAcquire(Utils.adjustTimeout(100L), TimeUnit.MILLISECONDS);
@@ -332,6 +362,10 @@
         Handler h1 = new Handler();
         Handler h2 = new Handler();
         SignalHandler orig = Signal.handle(signal, h1);
+        if (orig == SignalHandler.SIG_IGN) {
+            // SIG_IGN for TERM means it cannot be handled
+            return;
+        }
 
         try {
             SignalHandler prev = Signal.handle(signal, h2);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test that URL connections to multi-release jars can be runtime versioned
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarURLConnection
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.jar.JarFile;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class MultiReleaseJarURLConnection {
+    String userdir = System.getProperty("user.dir",".");
+    String urlFile = "jar:file:" + userdir + "/multi-release.jar!/";
+    String urlEntry = urlFile + "version/Version.java";
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildMultiReleaseJar();
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        Files.delete(Paths.get(userdir, "multi-release.jar"));
+    }
+
+    @Test
+    public void testRuntimeVersioning() throws Exception {
+        Assert.assertTrue(readAndCompare(new URL(urlEntry), "return 8"));
+        // #runtime is "magic"
+        Assert.assertTrue(readAndCompare(new URL(urlEntry + "#runtime"), "return 9"));
+        // #fragment or any other fragment is not magic
+        Assert.assertTrue(readAndCompare(new URL(urlEntry + "#fragment"), "return 8"));
+        // cached entities not affected
+        Assert.assertTrue(readAndCompare(new URL(urlEntry), "return 8"));
+    }
+
+    @Test
+    public void testCachedJars() throws Exception {
+        URL rootUrl = new URL(urlFile);
+        JarURLConnection juc = (JarURLConnection)rootUrl.openConnection();
+        JarFile rootJar = juc.getJarFile();
+        JarFile.Release root = rootJar.getVersion();
+
+        URL runtimeUrl = new URL(urlFile + "#runtime");
+        juc = (JarURLConnection)runtimeUrl.openConnection();
+        JarFile runtimeJar = juc.getJarFile();
+        JarFile.Release runtime = runtimeJar.getVersion();
+        Assert.assertNotEquals(root, runtime);
+
+        juc = (JarURLConnection)rootUrl.openConnection();
+        JarFile jar = juc.getJarFile();
+        Assert.assertEquals(jar.getVersion(), root);
+        Assert.assertEquals(jar, rootJar);
+
+        juc = (JarURLConnection)runtimeUrl.openConnection();
+        jar = juc.getJarFile();
+        Assert.assertEquals(jar.getVersion(), runtime);
+        Assert.assertEquals(jar, runtimeJar);
+
+        rootJar.close();
+        runtimeJar.close();
+        jar.close(); // probably not needed
+    }
+
+    private boolean readAndCompare(URL url, String match) throws Exception {
+        boolean result;
+        // necessary to do it this way, instead of openStream(), so we can
+        // close underlying JarFile, otherwise windows can't delete the file
+        URLConnection conn = url.openConnection();
+        try (InputStream is = conn.getInputStream()) {
+            byte[] bytes = is.readAllBytes();
+            result = (new String(bytes)).contains(match);
+        }
+        if (conn instanceof JarURLConnection) {
+            ((JarURLConnection)conn).getJarFile().close();
+        }
+        return result;
+    }
+}
--- a/jdk/test/tools/pack200/Pack200Test.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/tools/pack200/Pack200Test.java	Wed Jul 05 21:24:14 2017 +0200
@@ -81,7 +81,9 @@
                 System.out.println("Packing [" + in.toString() + "]");
                 // Call the packer
                 Utils.pack(jarFile, packFile);
+                System.out.println("Done Packing [" + in.toString() + "]");
                 jarFile.close();
+                System.out.println("Start leak check");
                 leakCheck();
 
                 System.out.println("  Unpacking using java unpacker");
--- a/jdk/test/tools/pack200/Utils.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/jdk/test/tools/pack200/Utils.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -324,6 +324,9 @@
     private static void findFiles0(File startDir, List<File> list,
                                     FileFilter filter) throws IOException {
         File[] foundFiles = startDir.listFiles(filter);
+        if (foundFiles == null) {
+            return;
+        }
         list.addAll(Arrays.asList(foundFiles));
         File[] dirs = startDir.listFiles(DIR_FILTER);
         for (File dir : dirs) {
--- a/langtools/.hgtags	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/.hgtags	Wed Jul 05 21:24:14 2017 +0200
@@ -349,3 +349,4 @@
 3f60a4808377a276f6398ff19e61c1b9086f4d97 jdk-9+104
 81bd82222f8a1f2b291a44a49e063973caa4e73b jdk-9+105
 dd05d3761a341143ef4a6b1a245e0960cc125b76 jdk-9+106
+7a0c343551497bd0e38ad69a77cc57d9f396615a jdk-9+107
--- a/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, 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
@@ -28,12 +28,7 @@
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
-import java.util.Locale;
 import java.util.Map;
-import java.util.logging.Logger;
-import java.util.logging.Level;
-
-import static java.util.logging.Level.*;
 
 /**
  * Provides methods for locating tool providers, for example,
@@ -45,47 +40,6 @@
  */
 public class ToolProvider {
 
-    private static final String propertyName = "sun.tools.ToolProvider";
-    private static final String loggerName   = "javax.tools";
-
-    /*
-     * Define the system property "sun.tools.ToolProvider" to enable
-     * debugging:
-     *
-     *     java ... -Dsun.tools.ToolProvider ...
-     */
-    static <T> T trace(Level level, Object reason) {
-        // NOTE: do not make this method private as it affects stack traces
-        try {
-            if (System.getProperty(propertyName) != null) {
-                StackTraceElement[] st = Thread.currentThread().getStackTrace();
-                String method = "???";
-                String cls = ToolProvider.class.getName();
-                if (st.length > 2) {
-                    StackTraceElement frame = st[2];
-                    method = String.format((Locale)null, "%s(%s:%s)",
-                                           frame.getMethodName(),
-                                           frame.getFileName(),
-                                           frame.getLineNumber());
-                    cls = frame.getClassName();
-                }
-                Logger logger = Logger.getLogger(loggerName);
-                if (reason instanceof Throwable) {
-                    logger.logp(level, cls, method,
-                                reason.getClass().getName(), (Throwable)reason);
-                } else {
-                    logger.logp(level, cls, method, String.valueOf(reason));
-                }
-            }
-        } catch (SecurityException ex) {
-            System.err.format((Locale)null, "%s: %s; %s%n",
-                              ToolProvider.class.getName(),
-                              reason,
-                              ex.getLocalizedMessage());
-        }
-        return null;
-    }
-
     private static final String systemJavaCompilerName
         = "com.sun.tools.javac.api.JavacTool";
 
@@ -153,7 +107,7 @@
         try {
             return c.asSubclass(clazz).newInstance();
         } catch (InstantiationException | IllegalAccessException | RuntimeException | Error e) {
-            return trace(WARNING, e);
+            throw new Error(e);
         }
     }
 
@@ -164,7 +118,7 @@
             try {
                 c = Class.forName(name, false, ClassLoader.getSystemClassLoader());
             } catch (ClassNotFoundException | RuntimeException | Error e) {
-                return trace(WARNING, e);
+                throw new Error(e);
             }
             toolClasses.put(name, new WeakReference<>(c));
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 21:24:14 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
@@ -155,8 +155,6 @@
         allowDefaultMethods = source.allowDefaultMethods();
         allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
         sourceName = source.name;
-        relax = (options.isSet("-retrofit") ||
-                options.isSet("-relax"));
         useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
 
         statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
@@ -168,10 +166,6 @@
         recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
     }
 
-    /** Switch: relax some constraints for retrofit mode.
-     */
-    boolean relax;
-
     /** Switch: support target-typing inference
      */
     boolean allowPoly;
@@ -1025,8 +1019,7 @@
                         log.error(tree.pos(),
                                   "default.allowed.in.intf.annotation.member");
                 }
-                if (isDefaultMethod || (tree.sym.flags() & (ABSTRACT | NATIVE)) == 0 &&
-                    !relax)
+                if (isDefaultMethod || (tree.sym.flags() & (ABSTRACT | NATIVE)) == 0)
                     log.error(tree.pos(), "missing.meth.body.or.decl.abstract");
             } else if ((tree.sym.flags() & (ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) {
                 if ((owner.flags() & INTERFACE) != 0) {
@@ -4384,8 +4377,7 @@
         // If this is a non-abstract class, check that it has no abstract
         // methods or unimplemented methods of an implemented interface.
         if ((c.flags() & (ABSTRACT | INTERFACE)) == 0) {
-            if (!relax)
-                chk.checkAllDefined(tree.pos(), c);
+            chk.checkAllDefined(tree.pos(), c);
         }
 
         if ((c.flags() & ANNOTATION) != 0) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Jul 05 21:24:14 2017 +0200
@@ -81,8 +81,6 @@
     private final Types types;
     private final TypeAnnotations typeAnnotations;
     private final JCDiagnostic.Factory diags;
-    private boolean warnOnSyntheticConflicts;
-    private boolean suppressAbortOnBadClassFile;
     private final JavaFileManager fileManager;
     private final Source source;
     private final Profile profile;
@@ -130,8 +128,6 @@
         allowStrictMethodClashCheck = source.allowStrictMethodClashCheck();
         allowPrivateSafeVarargs = source.allowPrivateSafeVarargs();
         allowDiamondWithAnonymousClassCreation = source.allowDiamondWithAnonymousClassCreation();
-        warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
-        suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile");
         warnOnAccessToSensitiveMembers = options.isSet("warnOnAccessToSensitiveMembers");
 
         Target target = Target.instance(context);
@@ -269,8 +265,7 @@
      */
     public Type completionError(DiagnosticPosition pos, CompletionFailure ex) {
         log.error(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE, pos, "cant.access", ex.sym, ex.getDetailValue());
-        if (ex instanceof ClassFinder.BadClassFile
-                && !suppressAbortOnBadClassFile) throw new Abort();
+        if (ex instanceof ClassFinder.BadClassFile) throw new Abort();
         else return syms.errType;
     }
 
@@ -2632,12 +2627,7 @@
      */
     private void syntheticError(DiagnosticPosition pos, Symbol sym) {
         if (!sym.type.isErroneous()) {
-            if (warnOnSyntheticConflicts) {
-                log.warning(pos, "synthetic.name.conflict", sym, sym.location());
-            }
-            else {
-                log.error(pos, "synthetic.name.conflict", sym, sym.location());
-            }
+            log.error(pos, "synthetic.name.conflict", sym, sym.location());
         }
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Jul 05 21:24:14 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
@@ -44,9 +44,11 @@
 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
 
-import java.io.File;
-import java.io.FileWriter;
 import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -353,9 +355,9 @@
                         rsContext.attrMode(),
                         rsContext.step,
                         round);
-                File dotFile = new File(dependenciesFolder, filename);
-                try (FileWriter fw = new FileWriter(dotFile)) {
-                    fw.append(graph);
+                Path dotFile = Paths.get(dependenciesFolder, filename);
+                try (Writer w = Files.newBufferedWriter(dotFile)) {
+                    w.append(graph);
                 }
                 round++;
             }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Wed Jul 05 21:24:14 2017 +0200
@@ -267,7 +267,14 @@
      * @return true if successful, and false otherwise
      */
     public boolean handleOption(Option option, String value) {
-        return locations.handleOption(option, value);
+        switch (option) {
+            case ENCODING:
+                encodingName = value;
+                return true;
+
+            default:
+                return locations.handleOption(option, value);
+        }
     }
 
     /**
@@ -285,6 +292,7 @@
     // </editor-fold>
 
     // <editor-fold defaultstate="collapsed" desc="Encoding">
+    private String encodingName;
     private String defaultEncodingName;
     private String getDefaultEncodingName() {
         if (defaultEncodingName == null) {
@@ -295,11 +303,7 @@
     }
 
     public String getEncodingName() {
-        String encName = options.get(Option.ENCODING);
-        if (encName == null)
-            return getDefaultEncodingName();
-        else
-            return encName;
+        return (encodingName != null) ? encodingName : getDefaultEncodingName();
     }
 
     @SuppressWarnings("cast")
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Wed Jul 05 21:24:14 2017 +0200
@@ -425,7 +425,7 @@
         if (container.endsWith("bootmodules.jimage")) {
             System.err.println("Warning: reference to bootmodules.jimage replaced by jrt:");
             container = Locations.JRT_MARKER_FILE;
-        } else if (container.getFileName().toString().endsWith(".jimage")) {
+        } else if (container.getNameCount() > 0 && container.getFileName().toString().endsWith(".jimage")) {
             System.err.println("Warning: reference to " + container + " ignored");
             return;
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Jul 05 21:24:14 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
@@ -72,18 +72,6 @@
      */
     private boolean verbose;
 
-    /** Switch: scramble private field names.
-     */
-    private boolean scramble;
-
-    /** Switch: scramble all field names.
-     */
-    private boolean scrambleAll;
-
-    /** Switch: retrofit mode.
-     */
-    private boolean retrofit;
-
     /** Switch: emit source file attribute.
      */
     private boolean emitSourceFile;
@@ -184,9 +172,6 @@
         signatureGen = new CWSignatureGenerator(types);
 
         verbose        = options.isSet(VERBOSE);
-        scramble       = options.isSet("-scramble");
-        scrambleAll    = options.isSet("-scrambleAll");
-        retrofit       = options.isSet("-retrofit");
         genCrt         = options.isSet(XJCOV);
         debugstackmap  = options.isSet("debugstackmap");
 
@@ -491,26 +476,11 @@
         putChar(poolbuf, poolCountIdx, pool.pp);
     }
 
-    /** Given a field, return its name.
-     */
-    Name fieldName(Symbol sym) {
-        if (scramble && (sym.flags() & PRIVATE) != 0 ||
-            scrambleAll && (sym.flags() & (PROTECTED | PUBLIC)) == 0)
-            return names.fromString("_$" + sym.name.getIndex());
-        else
-            return sym.name;
-    }
-
     /** Given a symbol, return its name-and-type.
      */
     NameAndType nameType(Symbol sym) {
-        return new NameAndType(fieldName(sym),
-                               retrofit
-                               ? sym.erasure(types)
-                               : sym.externalType(types), types);
-        // if we retrofit, then the NameAndType has been read in as is
-        // and no change is necessary. If we compile normally, the
-        // NameAndType is generated from a symbol reference, and the
+        return new NameAndType(sym.name, sym.externalType(types), types);
+        // the NameAndType is generated from a symbol reference, and the
         // adjustment of adding an additional this$n parameter needs to be made.
     }
 
@@ -1055,10 +1025,10 @@
         databuf.appendChar(flags);
         if (dumpFieldModifiers) {
             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
-            pw.println("FIELD  " + fieldName(v));
+            pw.println("FIELD  " + v.name);
             pw.println("---" + flagNames(v.flags()));
         }
-        databuf.appendChar(pool.put(fieldName(v)));
+        databuf.appendChar(pool.put(v.name));
         databuf.appendChar(pool.put(typeSig(v.erasure(types))));
         int acountIdx = beginAttrs();
         int acount = 0;
@@ -1079,10 +1049,10 @@
         databuf.appendChar(flags);
         if (dumpMethodModifiers) {
             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
-            pw.println("METHOD  " + fieldName(m));
+            pw.println("METHOD  " + m.name);
             pw.println("---" + flagNames(m.flags()));
         }
-        databuf.appendChar(pool.put(fieldName(m)));
+        databuf.appendChar(pool.put(m.name));
         databuf.appendChar(pool.put(typeSig(m.externalType(types))));
         int acountIdx = beginAttrs();
         int acount = 0;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Jul 05 21:24:14 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
@@ -120,25 +120,11 @@
             : options.isSet(G_CUSTOM, "vars");
         genCrt = options.isSet(XJCOV);
         debugCode = options.isSet("debugcode");
-        allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
         allowBetterNullChecks = target.hasObjects();
         pool = new Pool(types);
 
         // ignore cldc because we cannot have both stackmap formats
         this.stackMap = StackMapFormat.JSR202;
-
-        // by default, avoid jsr's for simple finalizers
-        int setjsrlimit = 50;
-        String jsrlimitString = options.get("jsrlimit");
-        if (jsrlimitString != null) {
-            try {
-                setjsrlimit = Integer.parseInt(jsrlimitString);
-            } catch (NumberFormatException ex) {
-                // ignore ill-formed numbers for jsrlimit
-            }
-        }
-        this.jsrlimit = setjsrlimit;
-        this.useJsrLocally = false; // reset in visitTry
         annotate = Annotate.instance(context);
     }
 
@@ -148,19 +134,8 @@
     private final boolean varDebugInfo;
     private final boolean genCrt;
     private final boolean debugCode;
-    private final boolean allowInvokedynamic;
     private final boolean allowBetterNullChecks;
 
-    /** Default limit of (approximate) size of finalizer to inline.
-     *  Zero means always use jsr.  100 or greater means never use
-     *  jsr.
-     */
-    private final int jsrlimit;
-
-    /** True if jsr is used.
-     */
-    private boolean useJsrLocally;
-
     /** Code buffer, set by genMethod.
      */
     private Code code;
@@ -1339,31 +1314,11 @@
         // in a new environment which calls the finally block if there is one.
         final Env<GenContext> tryEnv = env.dup(tree, new GenContext());
         final Env<GenContext> oldEnv = env;
-        if (!useJsrLocally) {
-            useJsrLocally =
-                (stackMap == StackMapFormat.NONE) &&
-                (jsrlimit <= 0 ||
-                jsrlimit < 100 &&
-                estimateCodeComplexity(tree.finalizer)>jsrlimit);
-        }
         tryEnv.info.finalize = new GenFinalizer() {
             void gen() {
-                if (useJsrLocally) {
-                    if (tree.finalizer != null) {
-                        Code.State jsrState = code.state.dup();
-                        jsrState.push(Code.jsrReturnValue);
-                        tryEnv.info.cont =
-                            new Chain(code.emitJump(jsr),
-                                      tryEnv.info.cont,
-                                      jsrState);
-                    }
-                    Assert.check(tryEnv.info.gaps.length() % 2 == 0);
-                    tryEnv.info.gaps.append(code.curCP());
-                } else {
-                    Assert.check(tryEnv.info.gaps.length() % 2 == 0);
-                    tryEnv.info.gaps.append(code.curCP());
-                    genLast();
-                }
+                Assert.check(tryEnv.info.gaps.length() % 2 == 0);
+                tryEnv.info.gaps.append(code.curCP());
+                genLast();
             }
             void genLast() {
                 if (tree.finalizer != null)
@@ -1568,93 +1523,6 @@
             }
         }
 
-    /** Very roughly estimate the number of instructions needed for
-     *  the given tree.
-     */
-    int estimateCodeComplexity(JCTree tree) {
-        if (tree == null) return 0;
-        class ComplexityScanner extends TreeScanner {
-            int complexity = 0;
-            public void scan(JCTree tree) {
-                if (complexity > jsrlimit) return;
-                super.scan(tree);
-            }
-            public void visitClassDef(JCClassDecl tree) {}
-            public void visitDoLoop(JCDoWhileLoop tree)
-                { super.visitDoLoop(tree); complexity++; }
-            public void visitWhileLoop(JCWhileLoop tree)
-                { super.visitWhileLoop(tree); complexity++; }
-            public void visitForLoop(JCForLoop tree)
-                { super.visitForLoop(tree); complexity++; }
-            public void visitSwitch(JCSwitch tree)
-                { super.visitSwitch(tree); complexity+=5; }
-            public void visitCase(JCCase tree)
-                { super.visitCase(tree); complexity++; }
-            public void visitSynchronized(JCSynchronized tree)
-                { super.visitSynchronized(tree); complexity+=6; }
-            public void visitTry(JCTry tree)
-                { super.visitTry(tree);
-                  if (tree.finalizer != null) complexity+=6; }
-            public void visitCatch(JCCatch tree)
-                { super.visitCatch(tree); complexity+=2; }
-            public void visitConditional(JCConditional tree)
-                { super.visitConditional(tree); complexity+=2; }
-            public void visitIf(JCIf tree)
-                { super.visitIf(tree); complexity+=2; }
-            // note: for break, continue, and return we don't take unwind() into account.
-            public void visitBreak(JCBreak tree)
-                { super.visitBreak(tree); complexity+=1; }
-            public void visitContinue(JCContinue tree)
-                { super.visitContinue(tree); complexity+=1; }
-            public void visitReturn(JCReturn tree)
-                { super.visitReturn(tree); complexity+=1; }
-            public void visitThrow(JCThrow tree)
-                { super.visitThrow(tree); complexity+=1; }
-            public void visitAssert(JCAssert tree)
-                { super.visitAssert(tree); complexity+=5; }
-            public void visitApply(JCMethodInvocation tree)
-                { super.visitApply(tree); complexity+=2; }
-            public void visitNewClass(JCNewClass tree)
-                { scan(tree.encl); scan(tree.args); complexity+=2; }
-            public void visitNewArray(JCNewArray tree)
-                { super.visitNewArray(tree); complexity+=5; }
-            public void visitAssign(JCAssign tree)
-                { super.visitAssign(tree); complexity+=1; }
-            public void visitAssignop(JCAssignOp tree)
-                { super.visitAssignop(tree); complexity+=2; }
-            public void visitUnary(JCUnary tree)
-                { complexity+=1;
-                  if (tree.type.constValue() == null) super.visitUnary(tree); }
-            public void visitBinary(JCBinary tree)
-                { complexity+=1;
-                  if (tree.type.constValue() == null) super.visitBinary(tree); }
-            public void visitTypeTest(JCInstanceOf tree)
-                { super.visitTypeTest(tree); complexity+=1; }
-            public void visitIndexed(JCArrayAccess tree)
-                { super.visitIndexed(tree); complexity+=1; }
-            public void visitSelect(JCFieldAccess tree)
-                { super.visitSelect(tree);
-                  if (tree.sym.kind == VAR) complexity+=1; }
-            public void visitIdent(JCIdent tree) {
-                if (tree.sym.kind == VAR) {
-                    complexity+=1;
-                    if (tree.type.constValue() == null &&
-                        tree.sym.owner.kind == TYP)
-                        complexity+=1;
-                }
-            }
-            public void visitLiteral(JCLiteral tree)
-                { complexity+=1; }
-            public void visitTree(JCTree tree) {}
-            public void visitWildcard(JCWildcard tree) {
-                throw new AssertionError(this.getClass().getName());
-            }
-        }
-        ComplexityScanner scanner = new ComplexityScanner();
-        tree.accept(scanner);
-        return scanner.complexity;
-    }
-
     public void visitIf(JCIf tree) {
         int limit = code.nextreg;
         Chain thenExit = null;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Wed Jul 05 21:24:14 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
@@ -25,9 +25,10 @@
 
 package com.sun.tools.javac.main;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -73,7 +74,7 @@
 
     private String ownName;
     private Set<String> classNames;
-    private Set<File> files;
+    private Set<Path> files;
     private Map<Option, String> deferredFileManagerOptions;
     private Set<JavaFileObject> fileObjects;
     private final Options options;
@@ -153,8 +154,8 @@
         }
 
         @Override
-        public void addFile(File f) {
-            files.add(f);
+        public void addFile(Path p) {
+            files.add(p);
         }
 
         @Override
@@ -252,7 +253,7 @@
             } else {
                 fileObjects = new LinkedHashSet<>();
                 JavacFileManager jfm = (JavacFileManager) getFileManager();
-                for (JavaFileObject fo: jfm.getJavaFileObjectsFromFiles(files))
+                for (JavaFileObject fo: jfm.getJavaFileObjectsFromPaths(files))
                     fileObjects.add(fo);
             }
         }
@@ -583,8 +584,8 @@
         if (value == null) {
             return true;
         }
-        File file = new File(value);
-        if (file.exists() && !file.isDirectory()) {
+        Path file = Paths.get(value);
+        if (Files.exists(file) && !Files.isDirectory(file)) {
             error("err.file.not.directory", value);
             return false;
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/CommandLine.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/CommandLine.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2010, 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
@@ -27,9 +27,10 @@
 
 import java.io.IOException;
 import java.io.Reader;
-import java.io.FileReader;
-import java.io.BufferedReader;
 import java.io.StreamTokenizer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
 import com.sun.tools.javac.util.ListBuffer;
 
 /**
@@ -73,7 +74,7 @@
     private static void loadCmdFile(String name, ListBuffer<String> args)
         throws IOException
     {
-        try (Reader r = new BufferedReader(new FileReader(name))) {
+        try (Reader r = Files.newBufferedReader(Paths.get(name))) {
             StreamTokenizer st = new StreamTokenizer(r);
             st.resetSyntax();
             st.wordChars(' ', 255);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Jul 05 21:24:14 2017 +0200
@@ -389,10 +389,6 @@
 
         verbose       = options.isSet(VERBOSE);
         sourceOutput  = options.isSet(PRINTSOURCE); // used to be -s
-        stubOutput    = options.isSet("-stubs");
-        relax         = options.isSet("-relax");
-        printFlat     = options.isSet("-printflat");
-        encoding      = options.get(ENCODING);
         lineDebugInfo = options.isUnset(G_CUSTOM) ||
                         options.isSet(G_CUSTOM, "lines");
         genEndPos     = options.isSet(XJCOV) ||
@@ -447,21 +443,6 @@
      */
     public boolean sourceOutput;
 
-    /** Emit stub source files rather than class files.
-     */
-    public boolean stubOutput;
-
-    /** Switch: relax some constraints for producing the jsr14 prototype.
-     */
-    boolean relax;
-
-    /** Debug switch: Emit Java sources after inner class flattening.
-     */
-    public boolean printFlat;
-
-    /** The encoding to be used for source input.
-     */
-    public String encoding;
 
     /** Generate code with the LineNumberTable attribute for debugging
      */
@@ -611,7 +592,7 @@
     // where
         public boolean keepComments = false;
         protected boolean keepComments() {
-            return keepComments || sourceOutput || stubOutput;
+            return keepComments || sourceOutput;
         }
 
 
@@ -676,30 +657,6 @@
         }
     }
 
-    /** Emit plain Java source for a class.
-     *  @param env    The attribution environment of the outermost class
-     *                containing this class.
-     *  @param cdef   The class definition to be printed.
-     */
-    JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
-        JavaFileObject outFile
-            = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
-                                               cdef.sym.flatname.toString(),
-                                               JavaFileObject.Kind.SOURCE,
-                                               null);
-        if (inputFiles.contains(outFile)) {
-            log.error(cdef.pos(), "source.cant.overwrite.input.file", outFile);
-            return null;
-        } else {
-            try (BufferedWriter out = new BufferedWriter(outFile.openWriter())) {
-                new Pretty(out, true).printUnit(env.toplevel, cdef);
-                if (verbose)
-                    log.printVerbose("wrote.file", outFile);
-            }
-            return outFile;
-        }
-    }
-
     /** Generate code and emit a class file for a given class
      *  @param env    The attribution environment of the outermost class
      *                containing this class.
@@ -720,6 +677,30 @@
         return null;
     }
 
+    /** Emit plain Java source for a class.
+     *  @param env    The attribution environment of the outermost class
+     *                containing this class.
+     *  @param cdef   The class definition to be printed.
+     */
+    JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
+        JavaFileObject outFile
+           = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
+                                               cdef.sym.flatname.toString(),
+                                               JavaFileObject.Kind.SOURCE,
+                                               null);
+        if (inputFiles.contains(outFile)) {
+            log.error(cdef.pos(), "source.cant.overwrite.input.file", outFile);
+            return null;
+        } else {
+            try (BufferedWriter out = new BufferedWriter(outFile.openWriter())) {
+                new Pretty(out, true).printUnit(env.toplevel, cdef);
+                if (verbose)
+                    log.printVerbose("wrote.file", outFile);
+            }
+            return outFile;
+        }
+    }
+
     /** Compile a source file that has been accessed by the class finder.
      *  @param c          The class the source file of which needs to be compiled.
      */
@@ -898,12 +879,6 @@
     }
 
     /**
-     * Set needRootClasses to true, in JavaCompiler subclass constructor
-     * that want to collect public apis of classes supplied on the command line.
-     */
-    protected boolean needRootClasses = false;
-
-    /**
      * The list of classes explicitly supplied on the command line for compilation.
      * Not always populated.
      */
@@ -966,7 +941,7 @@
         // If generating source, or if tracking public apis,
         // then remember the classes declared in
         // the original compilation units listed on the command line.
-        if (needRootClasses || sourceOutput || stubOutput) {
+        if (sourceOutput) {
             ListBuffer<JCClassDecl> cdefs = new ListBuffer<>();
             for (JCCompilationUnit unit : roots) {
                 for (List<JCTree> defs = unit.defs;
@@ -1275,11 +1250,6 @@
             if (shouldStop(CompileState.FLOW))
                 return;
 
-            if (relax) {
-                results.add(env);
-                return;
-            }
-
             if (verboseCompilePolicy)
                 printNote("[flow " + env.enclClass.sym + "]");
             JavaFileObject prev = log.useSource(
@@ -1419,9 +1389,9 @@
             TreeMaker localMake = make.forToplevel(env.toplevel);
 
             if (env.tree.hasTag(JCTree.Tag.PACKAGEDEF)) {
-                if (!(stubOutput || sourceOutput || printFlat)) {
+                if (!(sourceOutput)) {
                     if (shouldStop(CompileState.LOWER))
-                        return;
+                       return;
                     List<JCTree> pdef = lower.translateTopLevelClass(env, env.tree, localMake);
                     if (pdef.head != null) {
                         Assert.check(pdef.tail.isEmpty());
@@ -1431,19 +1401,6 @@
                 return;
             }
 
-            if (stubOutput) {
-                //emit stub Java source file, only for compilation
-                //units enumerated explicitly on the command line
-                JCClassDecl cdef = (JCClassDecl)env.tree;
-                if (untranslated instanceof JCClassDecl &&
-                    rootClasses.contains((JCClassDecl)untranslated) &&
-                    ((cdef.mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
-                     cdef.sym.packge().getQualifiedName() == names.java_lang)) {
-                    results.add(new Pair<>(env, removeMethodBodies(cdef)));
-                }
-                return;
-            }
-
             if (shouldStop(CompileState.TRANSTYPES))
                 return;
 
@@ -1504,16 +1461,12 @@
         if (shouldStop(CompileState.GENERATE))
             return;
 
-        boolean usePrintSource = (stubOutput || sourceOutput || printFlat);
-
         for (Pair<Env<AttrContext>, JCClassDecl> x: queue) {
             Env<AttrContext> env = x.fst;
             JCClassDecl cdef = x.snd;
 
             if (verboseCompilePolicy) {
-                printNote("[generate "
-                               + (usePrintSource ? " source" : "code")
-                               + " " + cdef.sym + "]");
+                printNote("[generate " + (sourceOutput ? " source" : "code") + " " + cdef.sym + "]");
             }
 
             if (!taskListener.isEmpty()) {
@@ -1526,9 +1479,9 @@
                                       env.toplevel.sourcefile);
             try {
                 JavaFileObject file;
-                if (usePrintSource)
+                if (sourceOutput) {
                     file = printSource(env, cdef);
-                else {
+                } else {
                     if (fileManager.hasLocation(StandardLocation.NATIVE_HEADER_OUTPUT)
                             && jniWriter.needsHeader(cdef.sym)) {
                         jniWriter.write(cdef.sym);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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,9 +25,11 @@
 
 package com.sun.tools.javac.main;
 
-import java.io.File;
 import java.io.FileWriter;
 import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.LinkedHashMap;
@@ -238,13 +240,7 @@
 
     IMPLICIT("-implicit:", "opt.implicit", STANDARD, BASIC, ONEOF, "none", "class"),
 
-    ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER) {
-        @Override
-        public boolean process(OptionHelper helper, String option, String operand) {
-            return super.process(helper, option, operand);
-        }
-
-    },
+    ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER),
 
     SOURCE("-source", "opt.arg.release", "opt.source", STANDARD, BASIC) {
         @Override
@@ -537,16 +533,16 @@
         @Override
         public boolean process(OptionHelper helper, String option) {
             if (option.endsWith(".java") ) {
-                File f = new File(option);
-                if (!f.exists()) {
-                    helper.error("err.file.not.found", f);
+                Path p = Paths.get(option);
+                if (!Files.exists(p)) {
+                    helper.error("err.file.not.found", p);
                     return true;
                 }
-                if (!f.isFile()) {
-                    helper.error("err.file.not.file", f);
+                if (!Files.isRegularFile(p)) {
+                    helper.error("err.file.not.file", p);
                     return true;
                 }
-                helper.addFile(f);
+                helper.addFile(p);
             } else {
                 helper.addClassName(option);
             }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/OptionHelper.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/OptionHelper.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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,9 +25,10 @@
 
 package com.sun.tools.javac.main;
 
+import java.nio.file.Path;
+
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Log.PrefixKind;
-import java.io.File;
 
 /**
  * Helper object to be used by {@link Option#process}, providing access to
@@ -63,7 +64,7 @@
     abstract void error(String key, Object... args);
 
     /** Record a file to be compiled. */
-    abstract void addFile(File f);
+    abstract void addFile(Path p);
 
     /** Record the name of a class for annotation processing. */
     abstract void addClassName(String s);
@@ -112,8 +113,8 @@
         }
 
         @Override
-        public void addFile(File f) {
-            throw new IllegalArgumentException(f.getPath());
+        public void addFile(Path p) {
+            throw new IllegalArgumentException(p.toString());
         }
 
         @Override
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 21:24:14 2017 +0200
@@ -981,10 +981,6 @@
 compiler.err.synthetic.name.conflict=\
     the symbol {0} conflicts with a compiler-synthesized symbol in {1}
 
-# 0: symbol, 1: symbol
-compiler.warn.synthetic.name.conflict=\
-    the symbol {0} conflicts with a compiler-synthesized symbol in {1}
-
 compiler.err.throws.not.allowed.in.intf.annotation=\
     throws clause not allowed in @interface members
 
@@ -1334,16 +1330,6 @@
 compiler.misc.verbose.wrote.file=\
     [wrote {0}]
 
-## extra output when using -verbose (Retro)
-compiler.misc.verbose.retro=\
-    [retrofitting {0}]
-
-compiler.misc.verbose.retro.with=\
-    \tretrofitting {0} with {1}
-
-compiler.misc.verbose.retro.with.list=\
-    \tretrofitting {0} with type parameters {1}, supertype {2}, interfaces {3}
-
 ## extra output when using -verbose (code/ClassReader)
 # 0: string
 compiler.misc.verbose.loading=\
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties	Wed Jul 05 21:24:14 2017 +0200
@@ -124,20 +124,12 @@
     Don't accept generics in the language
 javac.opt.moreinfo=\
     Print extended information for type variables
-javac.opt.printflat=\
-    Print abstract syntax tree after inner class conversion
 javac.opt.printsearch=\
     Print information where classfiles are searched
 javac.opt.prompt=\
     Stop after each error
-javac.opt.retrofit=\
-    Retrofit existing classfiles with generic types
 javac.opt.s=\
     Emit java sources instead of classfiles
-javac.opt.scramble=\
-    Scramble private identifiers in bytecode
-javac.opt.scrambleall=\
-    Scramble package visible identifiers in bytecode
 javac.opt.version=\
     Version information
 javac.opt.arg.pathname=\
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/JavahTask.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/JavahTask.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, 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
@@ -170,12 +170,6 @@
             }
         },
 
-        new HiddenOption(false, "-stubs") {
-            void process(JavahTask task, String opt, String arg) {
-                 // ignored; for backwards compatibility
-            }
-        },
-
         new Option(false, "-v", "-verbose") {
             void process(JavahTask task, String opt, String arg) {
                 task.verbose = true;
@@ -454,8 +448,6 @@
         if (llni)
             g = new LLNI(doubleAlign, util);
         else {
-//            if (stubs)
-//                throw new BadArgs("jni.no.stubs");
             g = new JNI(util);
         }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CleanProperties.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CleanProperties.java	Wed Jul 05 21:24:14 2017 +0200
@@ -75,9 +75,7 @@
                              Map<String, PubApi> dependencyPublicApis,
                              int debugLevel,
                              boolean incremental,
-                             int numCores,
-                             Writer out,
-                             Writer err) {
+                             int numCores) {
         boolean rc = true;
         for (String pkgName : pkgSrcs.keySet()) {
             String pkgNameF = pkgName.replace('.',File.separatorChar);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java	Wed Jul 05 21:24:14 2017 +0200
@@ -42,6 +42,8 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
 
 import com.sun.tools.sjavac.comp.CompilationService;
 import com.sun.tools.sjavac.options.Options;
@@ -89,9 +91,7 @@
                              final Map<String, PubApi> dependencyPubapis,
                              int debugLevel,
                              boolean incremental,
-                             int numCores,
-                             final Writer out,
-                             final Writer err) {
+                             int numCores) {
 
         Log.debug("Performing CompileJavaPackages transform...");
 
@@ -219,7 +219,9 @@
             }
 
             String chunkId = id + "-" + String.valueOf(i);
+            Log log = Log.get();
             compilationCalls.add(() -> {
+                Log.setLogForCurrentThread(log);
                 CompilationSubResult result = sjavac.compile("n/a",
                                                              chunkId,
                                                              args.prepJavacArgs(),
@@ -227,8 +229,8 @@
                                                              cc.srcs,
                                                              visibleSources);
                 synchronized (lock) {
-                    safeWrite(result.stdout, out);
-                    safeWrite(result.stderr, err);
+                    Util.getLines(result.stdout).forEach(Log::info);
+                    Util.getLines(result.stderr).forEach(Log::error);
                 }
                 return result;
             });
@@ -246,8 +248,10 @@
                 subResults.add(fut.get());
             } catch (ExecutionException ee) {
                 Log.error("Compilation failed: " + ee.getMessage());
-            } catch (InterruptedException ee) {
-                Log.error("Compilation interrupted: " + ee.getMessage());
+                Log.error(ee);
+            } catch (InterruptedException ie) {
+                Log.error("Compilation interrupted: " + ie.getMessage());
+                Log.error(ie);
                 Thread.currentThread().interrupt();
             }
         }
@@ -292,16 +296,6 @@
         return rc;
     }
 
-    private void safeWrite(String str, Writer w) {
-        if (str.length() > 0) {
-            try {
-                w.write(str);
-            } catch (IOException e) {
-                Log.error("Could not print compilation output.");
-            }
-        }
-    }
-
     /**
      * Split up the sources into compile chunks. If old package dependents information
      * is available, sort the order of the chunks into the most dependent first!
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileProperties.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileProperties.java	Wed Jul 05 21:24:14 2017 +0200
@@ -83,9 +83,7 @@
                              Map<String, PubApi> dependencyPublicApis,
                              int debugLevel,
                              boolean incremental,
-                             int numCores,
-                             Writer out,
-                             Writer err) {
+                             int numCores) {
         boolean rc = true;
         for (String pkgName : pkgSrcs.keySet()) {
             String pkgNameF = Util.toFileSystemPath(pkgName);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CopyFile.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CopyFile.java	Wed Jul 05 21:24:14 2017 +0200
@@ -70,9 +70,7 @@
                              Map<String, PubApi> dependencyPubapis,
                              int debugLevel,
                              boolean incremental,
-                             int numCores,
-                             Writer out,
-                             Writer err)
+                             int numCores)
     {
         boolean rc = true;
         String dest_filename;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java	Wed Jul 05 21:24:14 2017 +0200
@@ -123,16 +123,11 @@
     // Setup transform that always exist.
     private CompileJavaPackages compileJavaPackages = new CompileJavaPackages();
 
-    // Where to send stdout and stderr.
-    private Writer out, err;
-
     // Command line options.
     private Options options;
 
-    JavacState(Options op, boolean removeJavacState, Writer o, Writer e) {
+    JavacState(Options op, boolean removeJavacState) {
         options = op;
-        out = o;
-        err = e;
         numCores = options.getNumCores();
         theArgs = options.getStateArgsString();
         binDir = Util.pathToFile(options.getDestDir());
@@ -294,8 +289,8 @@
     /**
      * Load a javac_state file.
      */
-    public static JavacState load(Options options, Writer out, Writer err) {
-        JavacState db = new JavacState(options, false, out, err);
+    public static JavacState load(Options options) {
+        JavacState db = new JavacState(options, false);
         Module  lastModule = null;
         Package lastPackage = null;
         Source  lastSource = null;
@@ -367,22 +362,22 @@
             noFileFound = true;
         } catch (IOException e) {
             Log.info("Dropping old javac_state because of errors when reading it.");
-            db = new JavacState(options, true, out, err);
+            db = new JavacState(options, true);
             foundCorrectVerNr = true;
             newCommandLine = false;
             syntaxError = false;
     }
         if (foundCorrectVerNr == false && !noFileFound) {
             Log.info("Dropping old javac_state since it is of an old version.");
-            db = new JavacState(options, true, out, err);
+            db = new JavacState(options, true);
         } else
         if (newCommandLine == true && !noFileFound) {
             Log.info("Dropping old javac_state since a new command line is used!");
-            db = new JavacState(options, true, out, err);
+            db = new JavacState(options, true);
         } else
         if (syntaxError == true) {
             Log.info("Dropping old javac_state since it contains syntax errors.");
-            db = new JavacState(options, true, out, err);
+            db = new JavacState(options, true);
         }
         db.prev.calculateDependents();
         return db;
@@ -812,9 +807,7 @@
                                     dependencyPublicApis,
                                     0,
                                     isIncremental(),
-                                    numCores,
-                                    out,
-                                    err);
+                                    numCores);
             if (!r)
                 rc = false;
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Log.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Log.java	Wed Jul 05 21:24:14 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
@@ -26,11 +26,24 @@
 package com.sun.tools.sjavac;
 
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.io.Writer;
+import java.util.Locale;
 
 /**
  * Utility class only for sjavac logging.
- * The log level can be set using for example --log=DEBUG on the sjavac command line.
+ *
+ * Logging in sjavac has special requirements when running in server/client
+ * mode. Most of the log messages is generated server-side, but the server
+ * is typically spawned by the client in the background, so the user usually
+ * does not see the server stdout/stderr. For this reason log messages needs
+ * to relayed back to the client that performed the request that generated the
+ * log message. To support this use case this class maintains a per-thread log
+ * instance so that each connected client can have its own instance that
+ * relays messages back to the requesting client.
+ *
+ * On the client-side (or when running sjavac without server-mode) there will
+ * typically just be one Log instance.
  *
  *  <p><b>This is NOT part of any supported API.
  *  If you write code that depends on this, you do so at your own risk.
@@ -38,61 +51,94 @@
  *  deletion without notice.</b>
  */
 public class Log {
-    private static PrintWriter out, err;
+
+    public enum Level {
+        ERROR,
+        WARN,
+        INFO,
+        DEBUG,
+        TRACE;
+    }
+
+    private static Log stdOutErr = new Log(new PrintWriter(System.out), new PrintWriter(System.err));
+    private static ThreadLocal<Log> loggers = new ThreadLocal<>();
+
+    protected PrintWriter err; // Used for error and warning messages
+    protected PrintWriter out; // Used for other messages
+    protected Level level = Level.INFO;
 
-    public final static int WARN = 1;
-    public final static int INFO = 2;
-    public final static int DEBUG = 3;
-    public final static int TRACE = 4;
-    private static int level = WARN;
+    public Log(Writer out, Writer err) {
+        this.out = out == null ? null : new PrintWriter(out, true);
+        this.err = err == null ? null : new PrintWriter(err, true);
+    }
+
+    public static void setLogForCurrentThread(Log log) {
+        loggers.set(log);
+    }
+
+    public static void setLogLevel(String l) {
+        setLogLevel(Level.valueOf(l.toUpperCase(Locale.US)));
+    }
+
+    public static void setLogLevel(Level l) {
+        get().level = l;
+    }
 
     static public void trace(String msg) {
-        if (level >= TRACE) {
-            out.println(msg);
-        }
+        log(Level.TRACE, msg);
     }
 
     static public void debug(String msg) {
-        if (level >= DEBUG) {
-            out.println(msg);
-        }
+        log(Level.DEBUG, msg);
     }
 
     static public void info(String msg) {
-        if (level >= INFO) {
-            out.println(msg);
-        }
+        log(Level.INFO, msg);
     }
 
     static public void warn(String msg) {
-        err.println(msg);
+        log(Level.WARN, msg);
     }
 
     static public void error(String msg) {
-        err.println(msg);
+        log(Level.ERROR, msg);
     }
 
-    static public void initializeLog(Writer o, Writer e) {
-        out = new PrintWriter(o);
-        err = new PrintWriter(e);
+    static public void error(Throwable t) {
+        log(Level.ERROR, t);
     }
 
-    static public void setLogLevel(String l) {
-        switch (l) {
-            case "warn": level = WARN; break;
-            case "info": level = INFO; break;
-            case "debug": level = DEBUG; break;
-            case "trace": level = TRACE; break;
-            default:
-                throw new IllegalArgumentException("No such log level \"" + l + "\"");
-        }
+    static public void log(Level l, String msg) {
+        get().printLogMsg(l, msg);
     }
 
-    static public boolean isTracing() {
-        return level >= TRACE;
+    public static void debug(Throwable t) {
+        log(Level.DEBUG, t);
+    }
+
+    public static void log(Level l, Throwable t) {
+        StringWriter sw = new StringWriter();
+        t.printStackTrace(new PrintWriter(sw, true));
+        log(l, sw.toString());
     }
 
     static public boolean isDebugging() {
-        return level >= DEBUG;
+        return get().isLevelLogged(Level.DEBUG);
+    }
+
+    protected boolean isLevelLogged(Level l) {
+        return l.ordinal() <= level.ordinal();
+    }
+
+    public static Log get() {
+        Log log = loggers.get();
+        return log != null ? log : stdOutErr;
+    }
+
+    protected void printLogMsg(Level msgLevel, String msg) {
+        if (isLevelLogged(msgLevel)) {
+            PrintWriter pw = msgLevel.ordinal() <= Level.WARN.ordinal() ? err : out;
+            pw.println(msg);
+        }
     }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Transformer.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Transformer.java	Wed Jul 05 21:24:14 2017 +0200
@@ -95,9 +95,7 @@
                       Map<String, PubApi>     dependencyApis,
                       int debugLevel,
                       boolean incremental,
-                      int numCores,
-                      Writer out,
-                      Writer err);
+                      int numCores);
 
     void setExtra(String e);
     void setExtra(Options args);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java	Wed Jul 05 21:24:14 2017 +0200
@@ -36,7 +36,9 @@
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.function.Function;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Utilities.
@@ -236,4 +238,10 @@
         int dotIndex = fileNameStr.indexOf('.');
         return dotIndex == -1 ? "" : fileNameStr.substring(dotIndex);
     }
+
+    public static Stream<String> getLines(String str) {
+        return str.isEmpty()
+                ? Stream.empty()
+                : Stream.of(str.split(Pattern.quote(System.lineSeparator())));
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java	Wed Jul 05 21:24:14 2017 +0200
@@ -51,7 +51,7 @@
 
     public static int run(String[] args, Writer out, Writer err) {
 
-        Log.initializeLog(out, err);
+        Log.setLogForCurrentThread(new Log(out, err));
 
         Options options;
         try {
@@ -61,6 +61,8 @@
             return -1;
         }
 
+        Log.setLogLevel(options.getLogLevel());
+
         Log.debug("==========================================================");
         Log.debug("Launching sjavac client with the following parameters:");
         Log.debug("    " + options.getStateArgsString());
@@ -68,24 +70,15 @@
 
         // Prepare sjavac object
         boolean useServer = options.getServerConf() != null;
-        Sjavac sjavac;
-        // Create an sjavac implementation to be used for compilation
-        if (useServer) {
-            try {
-                sjavac = new SjavacClient(options);
-            } catch (PortFileInaccessibleException e) {
-                Log.error("Port file inaccessible.");
-                return -1;
-            }
-        } else {
-            sjavac = new SjavacImpl();
-        }
+        Sjavac sjavac = useServer ? new SjavacClient(options) : new SjavacImpl();
 
-        int rc = sjavac.compile(args, out, err);
+        // Perform compilation
+        int rc = sjavac.compile(args);
 
         // If sjavac is running in the foreground we should shut it down at this point
-        if (!useServer)
+        if (!useServer) {
             sjavac.shutdown();
+        }
 
         return rc;
     }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java	Wed Jul 05 21:24:14 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
@@ -32,6 +32,7 @@
 import java.io.OutputStreamWriter;
 import java.io.PrintStream;
 import java.io.PrintWriter;
+import java.io.Reader;
 import java.io.Writer;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
@@ -40,6 +41,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Scanner;
+import java.util.stream.Stream;
 
 import com.sun.tools.sjavac.Log;
 import com.sun.tools.sjavac.Util;
@@ -50,6 +52,8 @@
 import com.sun.tools.sjavac.server.Sjavac;
 import com.sun.tools.sjavac.server.SjavacServer;
 
+import static java.util.stream.Collectors.joining;
+
 /**
  * Sjavac implementation that delegates requests to a SjavacServer.
  *
@@ -64,8 +68,6 @@
     // JavaCompiler instance for several compiles using the same id.
     private final String id;
     private final PortFile portFile;
-    private final String logfile;
-    private final String stdouterrfile;
 
     // Default keepalive for server is 120 seconds.
     // I.e. it will accept 120 seconds of inactivity before quitting.
@@ -86,7 +88,7 @@
     // Store the server conf settings here.
     private final String settings;
 
-    public SjavacClient(Options options) throws PortFileInaccessibleException {
+    public SjavacClient(Options options) {
         String tmpServerConf = options.getServerConf();
         String serverConf = (tmpServerConf!=null)? tmpServerConf : "";
         String tmpId = Util.extractStringOption("id", serverConf);
@@ -96,14 +98,7 @@
                                         .toAbsolutePath()
                                         .toString();
         String portfileName = Util.extractStringOption("portfile", serverConf, defaultPortfile);
-        try {
-            portFile = SjavacServer.getPortFile(portfileName);
-        } catch (PortFileInaccessibleException e) {
-            Log.error("Port file inaccessable: " + e);
-            throw e;
-        }
-        logfile = Util.extractStringOption("logfile", serverConf, portfileName + ".javaclog");
-        stdouterrfile = Util.extractStringOption("stdouterrfile", serverConf, portfileName + ".stdouterr");
+        portFile = SjavacServer.getPortFile(portfileName);
         sjavacForkCmd = Util.extractStringOption("sjavac", serverConf, "sjavac");
         int poolsize = Util.extractIntOption("poolsize", serverConf);
         keepalive = Util.extractIntOption("keepalive", serverConf, 120);
@@ -121,7 +116,7 @@
     }
 
     @Override
-    public int compile(String[] args, Writer stdout, Writer stderr) {
+    public int compile(String[] args) {
         int result = -1;
         try (Socket socket = tryConnect()) {
             PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
@@ -136,32 +131,36 @@
             // Read server response line by line
             String line;
             while (null != (line = in.readLine())) {
+                if (!line.contains(":")) {
+                    throw new AssertionError("Could not parse protocol line: >>\"" + line + "\"<<");
+                }
                 String[] typeAndContent = line.split(":", 2);
                 String type = typeAndContent[0];
                 String content = typeAndContent[1];
-                switch (type) {
-                case SjavacServer.LINE_TYPE_STDOUT:
-                    stdout.write(content);
-                    stdout.write('\n');
-                    break;
-                case SjavacServer.LINE_TYPE_STDERR:
-                    stderr.write(content);
-                    stderr.write('\n');
-                    break;
-                case SjavacServer.LINE_TYPE_RC:
+
+                try {
+                    Log.log(Log.Level.valueOf(type), "[server] " + content);
+                    continue;
+                } catch (IllegalArgumentException e) {
+                    // Parsing of 'type' as log level failed.
+                }
+
+                if (type.equals(SjavacServer.LINE_TYPE_RC)) {
                     result = Integer.parseInt(content);
-                    break;
                 }
             }
+        } catch (PortFileInaccessibleException e) {
+            Log.error("Port file inaccessible.");
+            result = CompilationSubResult.ERROR_FATAL;
         } catch (IOException ioe) {
-            Log.error("[CLIENT] Exception caught: " + ioe);
+            Log.error("IOException caught during compilation: " + ioe.getMessage());
+            Log.debug(ioe);
             result = CompilationSubResult.ERROR_FATAL;
-            ioe.printStackTrace(new PrintWriter(stderr));
         } catch (InterruptedException ie) {
             Thread.currentThread().interrupt(); // Restore interrupt
-            Log.error("[CLIENT] compile interrupted.");
+            Log.error("Compilation interrupted.");
+            Log.debug(ie);
             result = CompilationSubResult.ERROR_FATAL;
-            ie.printStackTrace(new PrintWriter(stderr));
         }
         return result;
     }
@@ -203,23 +202,22 @@
     private void makeSureServerIsRunning(PortFile portFile)
             throws IOException, InterruptedException {
 
-        portFile.lock();
-        portFile.getValues();
-        portFile.unlock();
+        if (portFile.exists()) {
+            portFile.lock();
+            portFile.getValues();
+            portFile.unlock();
 
-        if (portFile.containsPortInfo()) {
-            // Server seems to already be running
-            return;
+            if (portFile.containsPortInfo()) {
+                // Server seems to already be running
+                return;
+            }
         }
 
         // Fork a new server and wait for it to start
         SjavacClient.fork(sjavacForkCmd,
                           portFile,
-                          logfile,
                           poolsize,
-                          keepalive,
-                          System.err,
-                          stdouterrfile);
+                          keepalive);
     }
 
     @Override
@@ -230,51 +228,53 @@
     /*
      * Fork a server process process and wait for server to come around
      */
-    public static void fork(String sjavacCmd,
-                            PortFile portFile,
-                            String logfile,
-                            int poolsize,
-                            int keepalive,
-                            final PrintStream err,
-                            String stdouterrfile)
-                                    throws IOException, InterruptedException {
+    public static void fork(String sjavacCmd, PortFile portFile, int poolsize, int keepalive)
+            throws IOException, InterruptedException {
         List<String> cmd = new ArrayList<>();
         cmd.addAll(Arrays.asList(OptionHelper.unescapeCmdArg(sjavacCmd).split(" ")));
         cmd.add("--startserver:"
               + "portfile=" + portFile.getFilename()
-              + ",logfile=" + logfile
-              + ",stdouterrfile=" + stdouterrfile
               + ",poolsize=" + poolsize
               + ",keepalive="+ keepalive);
 
-        Process p = null;
+        Process serverProcess;
         Log.info("Starting server. Command: " + String.join(" ", cmd));
         try {
-            // If the cmd for some reason can't be executed (file not found, or
-            // is not executable) this will throw an IOException with a decent
-            // error message.
-            p = new ProcessBuilder(cmd)
-                        .redirectErrorStream(true)
-                        .redirectOutput(new File(stdouterrfile))
-                        .start();
+            // If the cmd for some reason can't be executed (file is not found,
+            // or is not executable for instance) this will throw an
+            // IOException and p == null.
+            serverProcess = new ProcessBuilder(cmd)
+                    .redirectErrorStream(true)
+                    .start();
+        } catch (IOException ex) {
+            // Message is typically something like:
+            // Cannot run program "xyz": error=2, No such file or directory
+            Log.error("Failed to create server process: " + ex.getMessage());
+            Log.debug(ex);
+            throw new IOException(ex);
+        }
 
+        // serverProcess != null at this point.
+        try {
             // Throws an IOException if no valid values materialize
             portFile.waitForValidValues();
-
         } catch (IOException ex) {
-            // Log and rethrow exception
-            Log.error("Faild to launch server.");
-            Log.error("    Message: " + ex.getMessage());
-            String rc = p == null || p.isAlive() ? "n/a" : "" + p.exitValue();
-            Log.error("    Server process exit code: " + rc);
-            Log.error("Server log:");
-            Log.error("------- Server log start -------");
-            try (Scanner s = new Scanner(new File(stdouterrfile))) {
-                while (s.hasNextLine())
-                    Log.error(s.nextLine());
+            // Process was started, but server failed to initialize. This could
+            // for instance be due to the JVM not finding the server class,
+            // or the server running in to some exception early on.
+            Log.error("Sjavac server failed to initialize: " + ex.getMessage());
+            Log.error("Process output:");
+            Reader serverStdoutStderr = new InputStreamReader(serverProcess.getInputStream());
+            try (BufferedReader br = new BufferedReader(serverStdoutStderr)) {
+                br.lines().forEach(Log::error);
             }
-            Log.error("------- Server log end ---------");
-            throw ex;
+            Log.error("<End of process output>");
+            try {
+                Log.error("Process exit code: " + serverProcess.exitValue());
+            } catch (IllegalThreadStateException e) {
+                // Server is presumably still running.
+            }
+            throw new IOException("Server failed to initialize: " + ex.getMessage(), ex);
         }
     }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/CompilationService.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/CompilationService.java	Wed Jul 05 21:24:14 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
@@ -95,11 +95,8 @@
             for (JavaFileObject jfo : fm.getJavaFileObjectsFromFiles(sourcesToCompileFiles))
                 explicitJFOs.append(SmartFileManager.locWrap(jfo, StandardLocation.SOURCE_PATH));
 
-            // Create a new logger
-            StringWriter stdoutLog = new StringWriter();
+            // Create a log to capture compiler output
             StringWriter stderrLog = new StringWriter();
-            PrintWriter stdout = new PrintWriter(stdoutLog);
-            PrintWriter stderr = new PrintWriter(stderrLog);
             com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
             PublicApiCollector pubApiCollector = new PublicApiCollector(context, explicitJFOs);
             PathAndPackageVerifier papVerifier = new PathAndPackageVerifier();
@@ -108,11 +105,10 @@
                 if (explicitJFOs.size() > 0) {
                     sfm.setVisibleSources(visibleSources);
                     sfm.cleanArtifacts();
-                    sfm.setLog(stdout);
 
                     // Do the compilation!
                     JavacTaskImpl task =
-                            (JavacTaskImpl) compiler.getTask(stderr,
+                            (JavacTaskImpl) compiler.getTask(new PrintWriter(stderrLog),
                                                              sfm,
                                                              null,
                                                              Arrays.asList(args),
@@ -144,7 +140,6 @@
 
             compilationResult.packagePubapis = pubApiCollector.getPubApis(true);
             compilationResult.dependencyPubapis = pubApiCollector.getPubApis(false);
-            compilationResult.stdout = stdoutLog.toString();
             compilationResult.stderr = stderrLog.toString();
             compilationResult.returnCode = rc.exitCode;
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java	Wed Jul 05 21:24:14 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
@@ -25,15 +25,14 @@
 
 package com.sun.tools.sjavac.comp;
 
-import java.io.Writer;
+import com.sun.tools.sjavac.Log;
+import com.sun.tools.sjavac.server.Sjavac;
+
 import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-import com.sun.tools.sjavac.Log;
-import com.sun.tools.sjavac.server.Sjavac;
-
 /**
  * An sjavac implementation that limits the number of concurrent calls by
  * wrapping invocations in Callables and delegating them to a FixedThreadPool.
@@ -55,10 +54,12 @@
     }
 
     @Override
-    public int compile(String[] args, Writer out, Writer err) {
+    public int compile(String[] args) {
+        Log log = Log.get();
         try {
             return pool.submit(() -> {
-                return delegate.compile(args, out, err);
+                Log.setLogForCurrentThread(log);
+                return delegate.compile(args);
             }).get();
         } catch (Exception e) {
             e.printStackTrace();
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -27,6 +27,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.io.Writer;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -68,7 +69,7 @@
 public class SjavacImpl implements Sjavac {
 
     @Override
-    public int compile(String[] args, Writer out, Writer err) {
+    public int compile(String[] args) {
         Options options;
         try {
             options = Options.parseArgs(args);
@@ -77,8 +78,6 @@
             return RC_FATAL;
         }
 
-        Log.setLogLevel(options.getLogLevel());
-
         if (!validateOptions(options))
             return RC_FATAL;
 
@@ -100,18 +99,21 @@
         if (stateDir == null) {
             // Prepare context. Direct logging to our byte array stream.
             Context context = new Context();
-            PrintWriter writer = new PrintWriter(err);
-            com.sun.tools.javac.util.Log.preRegister(context, writer);
+            StringWriter strWriter = new StringWriter();
+            PrintWriter printWriter = new PrintWriter(strWriter);
+            com.sun.tools.javac.util.Log.preRegister(context, printWriter);
             JavacFileManager.preRegister(context);
 
             // Prepare arguments
             String[] passThroughArgs = Stream.of(args)
                                              .filter(arg -> !arg.startsWith(Option.SERVER.arg))
                                              .toArray(String[]::new);
+            // Compile
+            Main.Result result = new Main("javac", printWriter).compile(passThroughArgs, context);
 
-            // Compile
-            com.sun.tools.javac.main.Main compiler = new com.sun.tools.javac.main.Main("javac", writer);
-            Main.Result result = compiler.compile(passThroughArgs, context);
+            // Process compiler output (which is always errors)
+            printWriter.flush();
+            Util.getLines(strWriter.toString()).forEach(Log::error);
 
             // Clean up
             JavaFileManager fileManager = context.get(JavaFileManager.class);
@@ -126,7 +128,7 @@
 
         } else {
             // Load the prev build state database.
-            JavacState javac_state = JavacState.load(options, out, err);
+            JavacState javac_state = JavacState.load(options);
 
             // Setup the suffix rules from the command line.
             Map<String, Transformer> suffixRules = new HashMap<>();
@@ -288,10 +290,12 @@
 
                 return rc[0] ? RC_OK : RC_FATAL;
             } catch (ProblemException e) {
+                // For instance make file list mismatch.
                 Log.error(e.getMessage());
+                Log.debug(e);
                 return RC_FATAL;
             } catch (Exception e) {
-                e.printStackTrace(new PrintWriter(err));
+                Log.error(e);
                 return RC_FATAL;
             }
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileManager.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileManager.java	Wed Jul 05 21:24:14 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
@@ -63,8 +63,6 @@
     Set<URI> visibleSources = new HashSet<>();
     // Map from modulename:packagename to artifacts.
     Map<String,Set<URI>> packageArtifacts = new HashMap<>();
-    // Where to print informational messages.
-    PrintWriter stdout;
 
     public SmartFileManager(JavaFileManager fileManager) {
         super(fileManager);
@@ -78,10 +76,6 @@
         packageArtifacts = new HashMap<>();
     }
 
-    public void setLog(PrintWriter pw) {
-        stdout = pw;
-    }
-
     /**
      * Set whether or not to use ct.sym as an alternate to rt.jar.
      */
@@ -188,7 +182,7 @@
         if (file == null) return file;
 
         if (location.equals(StandardLocation.NATIVE_HEADER_OUTPUT) && superFile instanceof JavaFileObject) {
-           file = new SmartFileObject((JavaFileObject) file, stdout);
+           file = new SmartFileObject((JavaFileObject) file);
            packageName = ":" + packageNameFromFileName(relativeName);
         }
         if (packageName.equals("")) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -49,11 +49,9 @@
 public class SmartFileObject implements JavaFileObject {
 
     JavaFileObject file;
-    PrintWriter stdout;
 
-    public SmartFileObject(JavaFileObject r, PrintWriter pw) {
+    public SmartFileObject(JavaFileObject r) {
         file = r;
-        stdout = pw;
     }
 
     @Override
@@ -113,7 +111,7 @@
         } catch (FileNotFoundException | NoSuchFileException e) {
             // Perfectly ok.
         }
-        return new SmartWriter(file, s.toString(), file.getName(), stdout);
+        return new SmartWriter(file, s.toString(), file.getName());
     }
 
     @DefinedBy(Api.COMPILER)
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartWriter.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartWriter.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -25,6 +25,8 @@
 
 package com.sun.tools.sjavac.comp;
 
+import com.sun.tools.sjavac.Log;
+
 import java.io.*;
 import javax.tools.JavaFileObject;
 
@@ -45,19 +47,17 @@
     JavaFileObject file;
     String oldContent;
     StringWriter newContent = new StringWriter();
-    PrintWriter stdout;
     boolean closed;
-    public SmartWriter(JavaFileObject f, String s, String n, PrintWriter pw) {
+
+    public SmartWriter(JavaFileObject f, String s, String n) {
         name = n;
         file = f;
         oldContent = s;
         newContent = new StringWriter();
-        stdout = pw;
         closed = false;
     }
 
-    public void write(char[] chars, int i, int i1)
-    {
+    public void write(char[] chars, int i, int i1) {
         newContent.write(chars, i, i1);
     }
 
@@ -70,7 +70,7 @@
             try (Writer writer = file.openWriter()) {
                 writer.write(s);
             }
-            stdout.println("Writing "+file.getName().substring(p+1));
+            Log.debug("Writing " + file.getName().substring(p + 1));
         }
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java	Wed Jul 05 21:24:14 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
@@ -25,6 +25,10 @@
 
 package com.sun.tools.sjavac.server;
 
+import com.sun.tools.sjavac.Log;
+
+import java.io.FileWriter;
+import java.io.IOException;
 import java.io.Writer;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -53,8 +57,8 @@
     private TimerTask idlenessTimerTask;
 
     public IdleResetSjavac(Sjavac delegate,
-                            Terminable toShutdown,
-                            long idleTimeout) {
+                           Terminable toShutdown,
+                           long idleTimeout) {
         this.delegate = delegate;
         this.toShutdown = toShutdown;
         this.idleTimeout = idleTimeout;
@@ -62,10 +66,10 @@
     }
 
     @Override
-    public int compile(String[] args, Writer out, Writer err) {
+    public int compile(String[] args) {
         startCall();
         try {
-            return delegate.compile(args, out, err);
+            return delegate.compile(args);
         } finally {
             endCall();
         }
@@ -95,6 +99,7 @@
             throw new IllegalStateException("Idle timeout already scheduled");
         idlenessTimerTask = new TimerTask() {
             public void run() {
+                Log.setLogForCurrentThread(ServerMain.getErrorLog());
                 toShutdown.shutdown("Server has been idle for " + (idleTimeout / 1000) + " seconds.");
             }
         };
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/LinePrefixFilterWriter.java	Wed Jul 05 21:22:48 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.sjavac.server;
-
-import java.io.FilterWriter;
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Inserts {@literal prefix} in front of each line written.
- *
- * A line is considered to be terminated by any one of a line feed, a carriage
- * return, or a carriage return followed immediately by a line feed.
- */
-public class LinePrefixFilterWriter extends FilterWriter {
-
-    private final String prefix;
-    private boolean atBeginningOfLine = true;
-    private char lastChar = '\0';
-
-    protected LinePrefixFilterWriter(Writer out, String prefix) {
-        super(out);
-        this.prefix = prefix;
-    }
-
-    @Override
-    public void write(String str, int off, int len) throws IOException {
-        for (int i = 0; i < len; i++) {
-            write(str.charAt(off + i));
-        }
-    }
-
-    @Override
-    public void write(char[] cbuf, int off, int len) throws IOException {
-        for (int i = 0; i < len; i++) {
-            write(cbuf[off + i]);
-        }
-    }
-
-    @Override
-    public void write(int c) throws IOException {
-        if (lastChar == '\r' && c == '\n') {
-            // Second character of CR+LF sequence.
-            // Do nothing. We already started a new line on last character.
-        } else {
-            if (atBeginningOfLine) {
-                super.write(prefix, 0, prefix.length());
-            }
-            super.write(c);
-            atBeginningOfLine = c == '\r' || c == '\n';
-        }
-        lastChar = (char) c;
-    }
-}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java	Wed Jul 05 21:24:14 2017 +0200
@@ -81,10 +81,15 @@
      * Create a new portfile.
      * @param fn is the path to the file.
      */
-    public PortFile(String fn) throws PortFileInaccessibleException {
+    public PortFile(String fn) {
         filename = fn;
         file = new File(filename);
         stopFile = new File(filename+".stop");
+        containsPortInfo = false;
+        lock = null;
+    }
+
+    private void initializeChannel() throws PortFileInaccessibleException {
         try {
             rwfile = new RandomAccessFile(file, "rw");
         } catch (FileNotFoundException e) {
@@ -94,14 +99,15 @@
         // The rwfile should only be readable by the owner of the process
         // and no other! How do we do that on a RandomAccessFile?
         channel = rwfile.getChannel();
-        containsPortInfo = false;
-        lock = null;
     }
 
     /**
      * Lock the port file.
      */
     public void lock() throws IOException, InterruptedException {
+        if (channel == null) {
+            initializeChannel();
+        }
         lockSem.acquire();
         lock = channel.lock();
     }
@@ -204,8 +210,8 @@
         if (stopFile.exists()) {
             try {
                 stopFile.delete();
-            } catch (Exception e)
-            {}
+            } catch (Exception e) {
+            }
             return true;
         }
         return false;
@@ -215,7 +221,9 @@
      * Unlock the port file.
      */
     public void unlock() throws IOException {
-        Assert.check(lock != null);
+        if (lock == null) {
+            return;
+        }
         lock.release();
         lock = null;
         lockSem.release();
@@ -230,9 +238,11 @@
         long timeout = startTime + getServerStartupTimeoutSeconds() * 1000;
         while (true) {
             Log.debug("Looking for valid port file values...");
-            lock();
-            getValues();
-            unlock();
+            if (exists()) {
+                lock();
+                getValues();
+                unlock();
+            }
             if (containsPortInfo) {
                 Log.debug("Valid port file values found after " + (System.currentTimeMillis() - startTime) + " ms");
                 return;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFileMonitor.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFileMonitor.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -25,6 +25,8 @@
 
 package com.sun.tools.sjavac.server;
 
+import com.sun.tools.sjavac.Log;
+
 import java.io.IOException;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -56,8 +58,11 @@
     }
 
     public void start() {
+        Log log = Log.get();
         TimerTask shutdownCheck = new TimerTask() {
             public void run() {
+                Log.setLogForCurrentThread(log);
+                Log.debug("Checking port file status...");
                 try {
                     if (!portFile.exists()) {
                         // Time to quit because the portfile was deleted by another
@@ -74,12 +79,11 @@
                         server.shutdown("Quitting because portfile is now owned by another javac server!");
                     }
                 } catch (IOException e) {
-                    e.printStackTrace(server.theLog);
-                    server.flushLog();
+                    Log.error("IOException caught in PortFileMonitor.");
+                    Log.debug(e);
                 } catch (InterruptedException e) {
                     Thread.currentThread().interrupt();
-                    e.printStackTrace(server.theLog);
-                    server.flushLog();
+                    Log.error(e);
                 }
             }
         };
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java	Wed Jul 05 21:24:14 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
@@ -25,19 +25,16 @@
 
 package com.sun.tools.sjavac.server;
 
-import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_RC;
-import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_STDERR;
-import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_STDOUT;
+import com.sun.tools.sjavac.Log;
+import com.sun.tools.sjavac.Util;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.Writer;
 import java.net.Socket;
+import java.nio.file.Path;
 
-import com.sun.tools.sjavac.AutoFlushWriter;
-import com.sun.tools.sjavac.Log;
+import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_RC;
 
 
 /**
@@ -56,7 +53,7 @@
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public class RequestHandler implements Runnable {
+public class RequestHandler extends Thread {
 
     private final Socket socket;
     private final Sjavac sjavac;
@@ -68,9 +65,30 @@
 
     @Override
     public void run() {
+
         try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
              PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
 
+            // Set up logging for this thread. Stream back logging messages to
+            // client on the format format "level:msg".
+            Log.setLogForCurrentThread(new Log(out, out) {
+                @Override
+                protected boolean isLevelLogged(Level l) {
+                    // Make sure it is up to the client to decide whether or
+                    // not this message should be displayed.
+                    return true;
+                }
+
+                @Override
+                protected void printLogMsg(Level msgLevel, String msg) {
+                    // Follow sjavac server/client protocol: Send one line
+                    // at a time and prefix with message with "level:".
+                    Util.getLines(msg)
+                        .map(line -> msgLevel + ":" + line)
+                        .forEach(line -> super.printLogMsg(msgLevel, line));
+                }
+            });
+
             // Read argument array
             int n = Integer.parseInt(in.readLine());
             String[] args = new String[n];
@@ -78,23 +96,32 @@
                 args[i] = in.readLine();
             }
 
+            // If there has been any internal errors, notify client
+            checkInternalErrorLog();
+
             // Perform compilation
-            Writer stdout = new LinePrefixFilterWriter(new AutoFlushWriter(out), LINE_TYPE_STDOUT + ":");
-            Writer stderr = new LinePrefixFilterWriter(new AutoFlushWriter(out), LINE_TYPE_STDERR + ":");
-            int rc = sjavac.compile(args, stdout, stderr);
-            stdout.flush();
-            stderr.flush();
+            int rc = sjavac.compile(args);
 
             // Send return code back to client
             out.println(LINE_TYPE_RC + ":" + rc);
 
+            // Check for internal errors again.
+            checkInternalErrorLog();
         } catch (Exception ex) {
             // Not much to be done at this point. The client side request
             // code will most likely throw an IOException and the
             // compilation will fail.
-            StringWriter sw = new StringWriter();
-            ex.printStackTrace(new PrintWriter(sw));
-            Log.error(sw.toString());
+            Log.error(ex);
+        } finally {
+            Log.setLogForCurrentThread(null);
+        }
+    }
+
+    private void checkInternalErrorLog() {
+        Path errorLog = ServerMain.getErrorLog().getLogDestination();
+        if (errorLog != null) {
+            Log.error("Server has encountered an internal error. See " + errorLog.toAbsolutePath()
+                    + " for details.");
         }
     }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java	Wed Jul 05 21:24:14 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
@@ -25,10 +25,20 @@
 
 package com.sun.tools.sjavac.server;
 
+import java.io.FileWriter;
+import java.io.FilterOutputStream;
+import java.io.FilterWriter;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.lang.Thread.UncaughtExceptionHandler;
 
 import com.sun.tools.sjavac.Log;
+import com.sun.tools.sjavac.Log.Level;
+import com.sun.tools.sjavac.server.log.LazyInitFileLog;
+import com.sun.tools.sjavac.server.log.LoggingOutputStream;
+
+import static com.sun.tools.sjavac.Log.Level.ERROR;
+import static com.sun.tools.sjavac.Log.Level.INFO;
 
 /**
  *  <p><b>This is NOT part of any supported API.
@@ -37,20 +47,40 @@
  *  deletion without notice.</b>
  */
 public class ServerMain {
+
+    // For logging server internal (non request specific) errors.
+    private static LazyInitFileLog errorLog;
+
     public static int run(String[] args) {
 
-        Log.initializeLog(new OutputStreamWriter(System.out),
-                          new OutputStreamWriter(System.err));
+        // Under normal operation, all logging messages generated server-side
+        // are due to compilation requests. These logging messages should
+        // be relayed back to the requesting client rather than written to the
+        // server log. The only messages that should be written to the server
+        // log (in production mode) should be errors,
+        Log.setLogForCurrentThread(errorLog = new LazyInitFileLog("server.log"));
+        Log.setLogLevel(ERROR); // should be set to ERROR.
+
+        // Make sure no exceptions go under the radar
+        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
+            Log.setLogForCurrentThread(errorLog);
+            Log.error(e);
+        });
+
+        // Inevitably someone will try to print messages using System.{out,err}.
+        // Make sure this output also ends up in the log.
+        System.setOut(new PrintStream(new LoggingOutputStream(System.out, INFO, "[stdout] ")));
+        System.setErr(new PrintStream(new LoggingOutputStream(System.err, ERROR, "[stderr] ")));
 
         // Any options other than --startserver?
         if (args.length > 1) {
-            System.err.println("When spawning a background server, only a single --startserver argument is allowed.");
+            Log.error("When spawning a background server, only a single --startserver argument is allowed.");
             return 1;
         }
 
         int exitCode;
         try {
-            SjavacServer server = new SjavacServer(args[0], System.err);
+            SjavacServer server = new SjavacServer(args[0]);
             exitCode = server.startServer();
         } catch (IOException | InterruptedException ex) {
             ex.printStackTrace();
@@ -59,4 +89,8 @@
 
         return exitCode;
     }
+
+    public static LazyInitFileLog getErrorLog() {
+        return errorLog;
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java	Wed Jul 05 21:24:14 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,6 +42,6 @@
     final static int RC_FATAL = -1;
     final static int RC_OK = 0;
 
-    int compile(String[] args, Writer stdout, Writer stderr);
+    int compile(String[] args);
     void shutdown();
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
 package com.sun.tools.sjavac.server;
 
 import java.io.FileNotFoundException;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.io.PrintWriter;
@@ -39,6 +40,7 @@
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import com.sun.tools.sjavac.Log;
 import com.sun.tools.sjavac.Util;
 import com.sun.tools.sjavac.client.PortFileInaccessibleException;
 import com.sun.tools.sjavac.comp.PooledSjavac;
@@ -54,17 +56,12 @@
  */
 public class SjavacServer implements Terminable {
 
-    // Used in protocol to tell the content of each line
+    // Prefix of line containing return code.
     public final static String LINE_TYPE_RC = "RC";
-    public final static String LINE_TYPE_STDOUT = "STDOUT";
-    public final static String LINE_TYPE_STDERR = "STDERR";
 
     final private String portfilename;
-    final private String logfile;
-    final private String stdouterrfile;
     final private int poolsize;
     final private int keepalive;
-    final private PrintStream err;
 
     // The secret cookie shared between server and client through the port file.
     // Used to prevent clients from believing that they are communicating with
@@ -75,9 +72,6 @@
     // Accumulated build time, not counting idle time, used for logging purposes
     private long totalBuildTime;
 
-    // The javac server specific log file.
-    PrintWriter theLog;
-
     // The sjavac implementation to delegate requests to
     Sjavac sjavac;
 
@@ -92,40 +86,28 @@
     // For the client, all port files fetched, one per started javac server.
     // Though usually only one javac server is started by a client.
     private static Map<String, PortFile> allPortFiles;
-    private static Map<String, Long> maxServerMemory;
 
-    public SjavacServer(String settings, PrintStream err) throws FileNotFoundException {
+    public SjavacServer(String settings) throws FileNotFoundException {
         this(Util.extractStringOption("portfile", settings),
-             Util.extractStringOption("logfile", settings),
-             Util.extractStringOption("stdouterrfile", settings),
              Util.extractIntOption("poolsize", settings, Runtime.getRuntime().availableProcessors()),
-             Util.extractIntOption("keepalive", settings, 120),
-             err);
+             Util.extractIntOption("keepalive", settings, 120));
     }
 
     public SjavacServer(String portfilename,
-                        String logfile,
-                        String stdouterrfile,
                         int poolsize,
-                        int keepalive,
-                        PrintStream err)
+                        int keepalive)
                                 throws FileNotFoundException {
         this.portfilename = portfilename;
-        this.logfile = logfile;
-        this.stdouterrfile = stdouterrfile;
         this.poolsize = poolsize;
         this.keepalive = keepalive;
-        this.err = err;
-
-        myCookie = new Random().nextLong();
-        theLog = new PrintWriter(logfile);
+        this.myCookie = new Random().nextLong();
     }
 
 
     /**
      * Acquire the port file. Synchronized since several threads inside an smart javac wrapper client acquires the same port file at the same time.
      */
-    public static synchronized PortFile getPortFile(String filename) throws PortFileInaccessibleException {
+    public static synchronized PortFile getPortFile(String filename) {
         if (allPortFiles == null) {
             allPortFiles = new HashMap<>();
         }
@@ -170,26 +152,6 @@
     }
 
     /**
-     * Log this message.
-     */
-    public void log(String msg) {
-        if (theLog != null) {
-            theLog.println(msg);
-        } else {
-            System.err.println(msg);
-        }
-    }
-
-    /**
-     * Make sure the log is flushed.
-     */
-    public void flushLog() {
-        if (theLog != null) {
-            theLog.flush();
-        }
-    }
-
-    /**
      * Start a server using a settings string. Typically: "--startserver:portfile=/tmp/myserver,poolsize=3" and the string "portfile=/tmp/myserver,poolsize=3"
      * is sent as the settings parameter. Returns 0 on success, -1 on failure.
      */
@@ -203,7 +165,7 @@
             portFile.lock();
             portFile.getValues();
             if (portFile.containsPortInfo()) {
-                err.println("Javac server not started because portfile exists!");
+                Log.info("Javac server not started because portfile exists!");
                 portFile.unlock();
                 return -1;
             }
@@ -230,23 +192,23 @@
         portFileMonitor = new PortFileMonitor(portFile, this);
         portFileMonitor.start();
 
-        log("Sjavac server started. Accepting connections...");
-        log("    port: " + getPort());
-        log("    time: " + new java.util.Date());
-        log("    poolsize: " + poolsize);
-        flushLog();
+        Log.info("Sjavac server started. Accepting connections...");
+        Log.info("    port: " + getPort());
+        Log.info("    time: " + new java.util.Date());
+        Log.info("    poolsize: " + poolsize);
+
 
         keepAcceptingRequests.set(true);
         do {
             try {
                 Socket socket = serverSocket.accept();
-                new Thread(new RequestHandler(socket, sjavac)).start();
+                new RequestHandler(socket, sjavac).start();
             } catch (SocketException se) {
                 // Caused by serverSocket.close() and indicates shutdown
             }
         } while (keepAcceptingRequests.get());
 
-        log("Shutting down.");
+        Log.info("Shutting down.");
 
         // No more connections accepted. If any client managed to connect after
         // the accept() was interrupted but before the server socket is closed
@@ -254,8 +216,7 @@
         // IOException on the client side.
 
         long realTime = System.currentTimeMillis() - serverStart;
-        log("Total wall clock time " + realTime + "ms build time " + totalBuildTime + "ms");
-        flushLog();
+        Log.info("Total wall clock time " + realTime + "ms build time " + totalBuildTime + "ms");
 
         // Shut down
         sjavac.shutdown();
@@ -270,8 +231,7 @@
             return;
         }
 
-        log("Quitting: " + quitMsg);
-        flushLog();
+        Log.info("Quitting: " + quitMsg);
 
         portFileMonitor.shutdown(); // No longer any need to monitor port file
 
@@ -280,12 +240,12 @@
         try {
             portFile.delete();
         } catch (IOException | InterruptedException e) {
-            e.printStackTrace(theLog);
+            Log.error(e);
         }
         try {
             serverSocket.close();
         } catch (IOException e) {
-            e.printStackTrace(theLog);
+            Log.error(e);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/log/LazyInitFileLog.java	Wed Jul 05 21:24:14 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 com.sun.tools.sjavac.server.log;
+
+import com.sun.tools.sjavac.Log;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class LazyInitFileLog extends Log {
+
+    String baseFilename;
+    Path destination = null;
+
+    public LazyInitFileLog(String baseFilename) {
+        super(null, null);
+        this.baseFilename = baseFilename;
+    }
+
+    protected void printLogMsg(Level msgLevel, String msg) {
+        try {
+            // Lazily initialize out/err
+            if (out == null && isLevelLogged(msgLevel)) {
+                destination = getAvailableDestination();
+                out = err = new PrintWriter(new FileWriter(destination.toFile()), true);
+            }
+            // Proceed to log the message
+            super.printLogMsg(msgLevel, msg);
+        } catch (IOException e) {
+            // This could be bad. We might have run into an error and we can't
+            // log it. Resort to printing on stdout.
+            System.out.println("IO error occurred: " + e.getMessage());
+            System.out.println("Original message: [" + msgLevel + "] " + msg);
+        }
+    }
+
+    /**
+     * @return The first available path of baseFilename, baseFilename.1,
+     * basefilename.2, ...
+     */
+    private Path getAvailableDestination() {
+        Path p = Paths.get(baseFilename);
+        int i = 1;
+        while (Files.exists(p)) {
+            p = Paths.get(baseFilename + "." + i++);
+        }
+        return p;
+    }
+
+    public Path getLogDestination() {
+        return destination;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/log/LoggingOutputStream.java	Wed Jul 05 21:24:14 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.  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 com.sun.tools.sjavac.server.log;
+
+import com.sun.tools.sjavac.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class LoggingOutputStream extends FilterOutputStream {
+
+    private static final byte[] LINE_SEP = System.lineSeparator().getBytes();
+
+    private final Log.Level level;
+    private final String linePrefix;
+    private EolTrackingByteArrayOutputStream buf = new EolTrackingByteArrayOutputStream();
+
+    public LoggingOutputStream(OutputStream out, Log.Level level, String linePrefix) {
+        super(out);
+        this.level = level;
+        this.linePrefix = linePrefix;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        super.write(b);
+        buf.write(b);
+        if (buf.isLineComplete()) {
+            String line = new String(buf.toByteArray(), 0, buf.size() - LINE_SEP.length);
+            Log.log(level, linePrefix + line);
+            buf = new EolTrackingByteArrayOutputStream();
+        }
+    }
+
+    private static class EolTrackingByteArrayOutputStream extends ByteArrayOutputStream {
+        private static final byte[] EOL = System.lineSeparator().getBytes();
+        private boolean isLineComplete() {
+            if (count < EOL.length) {
+                return false;
+            }
+            for (int i = 0; i < EOL.length; i++) {
+                if (buf[count - EOL.length + i] != EOL[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Wed Jul 05 21:24:14 2017 +0200
@@ -26,6 +26,7 @@
 package jdk.internal.jshell.tool;
 
 import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
+import jdk.jshell.SourceCodeAnalysis.QualifiedNames;
 import jdk.jshell.SourceCodeAnalysis.Suggestion;
 
 import java.awt.event.ActionListener;
@@ -34,8 +35,12 @@
 import java.io.PrintStream;
 import java.io.UncheckedIOException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Supplier;
@@ -144,6 +149,11 @@
         bind(DOCUMENTATION_SHORTCUT, (ActionListener) evt -> documentation(repl));
         bind(CTRL_UP, (ActionListener) evt -> moveHistoryToSnippet(((EditingHistory) in.getHistory())::previousSnippet));
         bind(CTRL_DOWN, (ActionListener) evt -> moveHistoryToSnippet(((EditingHistory) in.getHistory())::nextSnippet));
+        for (FixComputer computer : FIX_COMPUTERS) {
+            for (String shortcuts : SHORTCUT_FIXES) {
+                bind(shortcuts + computer.shortcut, (ActionListener) evt -> fixes(computer));
+            }
+        }
     }
 
     @Override
@@ -216,6 +226,11 @@
     private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
     private static final String CTRL_UP = "\033\133\061\073\065\101"; //Ctrl-UP
     private static final String CTRL_DOWN = "\033\133\061\073\065\102"; //Ctrl-DOWN
+    private static final String[] SHORTCUT_FIXES = {
+        "\033\015", //Alt-Enter (Linux)
+        "\033\133\061\067\176", //F6/Alt-F1 (Mac)
+        "\u001BO3P" //Alt-F1 (Linux)
+    };
 
     private void documentation(JShellTool repl) {
         String buffer = in.getCursorBuffer().buffer.toString();
@@ -290,6 +305,185 @@
         history.fullHistoryReplace(source);
     }
 
+    //compute possible options/Fixes based on the selected FixComputer, present them to the user,
+    //and perform the selected one:
+    private void fixes(FixComputer computer) {
+        String input = prefix + in.getCursorBuffer().toString();
+        int cursor = prefix.length() + in.getCursorBuffer().cursor;
+        FixResult candidates = computer.compute(repl, input, cursor);
+
+        try {
+            final boolean printError = candidates.error != null && !candidates.error.isEmpty();
+            if (printError) {
+                in.println(candidates.error);
+            }
+            if (candidates.fixes.isEmpty()) {
+                in.beep();
+                if (printError) {
+                    in.redrawLine();
+                    in.flush();
+                }
+            } else if (candidates.fixes.size() == 1 && !computer.showMenu) {
+                if (printError) {
+                    in.redrawLine();
+                    in.flush();
+                }
+                candidates.fixes.get(0).perform(in);
+            } else {
+                List<Fix> fixes = new ArrayList<>(candidates.fixes);
+                fixes.add(0, new Fix() {
+                    @Override
+                    public String displayName() {
+                        return "Do nothing";
+                    }
+
+                    @Override
+                    public void perform(ConsoleReader in) throws IOException {
+                        in.redrawLine();
+                    }
+                });
+
+                Map<Character, Fix> char2Fix = new HashMap<>();
+                in.println();
+                for (int i = 0; i < fixes.size(); i++) {
+                    Fix fix = fixes.get(i);
+                    char2Fix.put((char) ('0' + i), fix);
+                    in.println("" + i + ": " + fixes.get(i).displayName());
+                }
+                in.print("Choice: ");
+                in.flush();
+                int read;
+
+                read = in.readCharacter();
+
+                Fix fix = char2Fix.get((char) read);
+
+                if (fix == null) {
+                    in.beep();
+                    fix = fixes.get(0);
+                }
+
+                in.println();
+
+                fix.perform(in);
+
+                in.flush();
+            }
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * A possible action which the user can choose to perform.
+     */
+    public interface Fix {
+        /**
+         * A name that should be shown to the user.
+         */
+        public String displayName();
+        /**
+         * Perform the given action.
+         */
+        public void perform(ConsoleReader in) throws IOException;
+    }
+
+    /**
+     * A factory for {@link Fix}es.
+     */
+    public abstract static class FixComputer {
+        private final char shortcut;
+        private final boolean showMenu;
+
+        /**
+         * Construct a new FixComputer. {@code shortcut} defines the key which should trigger this FixComputer.
+         * If {@code showMenu} is {@code false}, and this computer returns exactly one {@code Fix},
+         * no options will be show to the user, and the given {@code Fix} will be performed.
+         */
+        public FixComputer(char shortcut, boolean showMenu) {
+            this.shortcut = shortcut;
+            this.showMenu = showMenu;
+        }
+
+        /**
+         * Compute possible actions for the given code.
+         */
+        public abstract FixResult compute(JShellTool repl, String code, int cursor);
+    }
+
+    /**
+     * A list of {@code Fix}es with a possible error that should be shown to the user.
+     */
+    public static class FixResult {
+        public final List<Fix> fixes;
+        public final String error;
+
+        public FixResult(List<Fix> fixes, String error) {
+            this.fixes = fixes;
+            this.error = error;
+        }
+    }
+
+    private static final FixComputer[] FIX_COMPUTERS = new FixComputer[] {
+        new FixComputer('v', false) { //compute "Introduce variable" Fix:
+            @Override
+            public FixResult compute(JShellTool repl, String code, int cursor) {
+                String type = repl.analysis.analyzeType(code, cursor);
+                if (type == null) {
+                    return new FixResult(Collections.emptyList(), null);
+                }
+                return new FixResult(Collections.singletonList(new Fix() {
+                    @Override
+                    public String displayName() {
+                        return "Create variable";
+                    }
+                    @Override
+                    public void perform(ConsoleReader in) throws IOException {
+                        in.redrawLine();
+                        in.setCursorPosition(0);
+                        in.putString(type + "  = ");
+                        in.setCursorPosition(in.getCursorBuffer().cursor - 3);
+                        in.flush();
+                    }
+                }), null);
+            }
+        },
+        new FixComputer('i', true) { //compute "Add import" Fixes:
+            @Override
+            public FixResult compute(JShellTool repl, String code, int cursor) {
+                QualifiedNames res = repl.analysis.listQualifiedNames(code, cursor);
+                List<Fix> fixes = new ArrayList<>();
+                for (String fqn : res.getNames()) {
+                    fixes.add(new Fix() {
+                        @Override
+                        public String displayName() {
+                            return "import: " + fqn;
+                        }
+                        @Override
+                        public void perform(ConsoleReader in) throws IOException {
+                            repl.state.eval("import " + fqn + ";");
+                            in.println("Imported: " + fqn);
+                            in.redrawLine();
+                        }
+                    });
+                }
+                if (res.isResolvable()) {
+                    return new FixResult(Collections.emptyList(),
+                                         "\nThe identifier is resolvable in this context.");
+                } else {
+                    String error = "";
+                    if (fixes.isEmpty()) {
+                        error = "\nNo candidate fully qualified names found to import.";
+                    }
+                    if (!res.isUpToDate()) {
+                        error += "\nResults may be incomplete; try again later for complete results.";
+                    }
+                    return new FixResult(fixes, error);
+                }
+            }
+        }
+    };
+
     private static final class JShellUnixTerminal extends NoInterruptUnixTerminal {
 
         private final StopDetectingInputStream input;
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Wed Jul 05 21:24:14 2017 +0200
@@ -988,13 +988,19 @@
                 CommandKind.HELP_SUBJECT));
         registerCommand(new Command("shortcuts", "Describe shortcuts",
                 "Supported shortcuts include:\n\n" +
-                "<tab>       -- After entering the first few letters of a Java identifier,\n" +
-                "               a jshell command, or, in some cases, a jshell command argument,\n" +
-                "               press the <tab> key to complete the input.\n" +
-                "               If there is more than one completion, show possible completions.\n" +
-                "Shift-<tab> -- After the name and open parenthesis of a method or constructor invocation,\n" +
-                "               hold the <shift> key and press the <tab> to see a synopsis of all\n" +
-                "               matching methods/constructors.\n",
+                "<tab>            -- After entering the first few letters of a Java identifier,\n" +
+                "                    a jshell command, or, in some cases, a jshell command argument,\n" +
+                "                    press the <tab> key to complete the input.\n" +
+                "                    If there is more than one completion, show possible completions.\n" +
+                "Shift-<tab>      -- After the name and open parenthesis of a method or constructor invocation,\n" +
+                "                    hold the <shift> key and press the <tab> to see a synopsis of all\n" +
+                "                    matching methods/constructors.\n" +
+                "<fix-shortcut> v -- After a complete expression, press \"<fix-shortcut> v\" to introduce a new variable\n" +
+                "                    whose type is based on the type of the expression.\n" +
+                "                    The \"<fix-shortcut>\" is either Alt-F1 or Alt-Enter, depending on the platform.\n" +
+                "<fix-shortcut> i -- After an unresolvable identifier, press \"<fix-shortcut> i\" and jshell will propose\n" +
+                "                    possible fully qualified names based on the content of the specified classpath.\n" +
+                "                    The \"<fix-shortcut>\" is either Alt-F1 or Alt-Enter, depending on the platform.\n",
                 CommandKind.HELP_SUBJECT));
     }
 
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Jul 05 21:24:14 2017 +0200
@@ -420,7 +420,7 @@
         TaskFactory.AnalyzeTask at = trialCompile(guts);
         if (!at.hasErrors() && at.firstCuTree() != null) {
             return TreeDissector.createByFirstClass(at)
-                    .typeOfReturnStatement(at.messages(), state.maps::fullClassNameAndPackageToClass);
+                    .typeOfReturnStatement(at, state);
         }
         return null;
     }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Wed Jul 05 21:24:14 2017 +0200
@@ -346,10 +346,20 @@
      * @see JShell#onShutdown(java.util.function.Consumer)
      */
     public List<SnippetEvent> eval(String input) throws IllegalStateException {
-        checkIfAlive();
-        List<SnippetEvent> events = eval.eval(input);
-        events.forEach(this::notifyKeyStatusEvent);
-        return Collections.unmodifiableList(events);
+        SourceCodeAnalysisImpl a = sourceCodeAnalysis;
+        if (a != null) {
+            a.suspendIndexing();
+        }
+        try {
+            checkIfAlive();
+            List<SnippetEvent> events = eval.eval(input);
+            events.forEach(this::notifyKeyStatusEvent);
+            return Collections.unmodifiableList(events);
+        } finally {
+            if (a != null) {
+                a.resumeIndexing();
+            }
+        }
     }
 
     /**
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java	Wed Jul 05 21:24:14 2017 +0200
@@ -70,6 +70,28 @@
     public abstract String documentation(String input, int cursor);
 
     /**
+     * Infer the type of the given expression. The expression spans from the beginning of {@code code}
+     * to the given {@code cursor} position. Returns null if the type of the expression cannot
+     * be inferred.
+     *
+     * @param code the expression for which the type should be inferred
+     * @param cursor current cursor position in the given code
+     * @return the inferred type, or null if it cannot be inferred
+     */
+    public abstract String analyzeType(String code, int cursor);
+
+    /**
+     * List qualified names known for the simple name in the given code immediately
+     * to the left of the given cursor position. The qualified names are gathered by inspecting the
+     * classpath used by eval (see {@link JShell#addToClasspath(java.lang.String)}).
+     *
+     * @param code the expression for which the candidate qualified names should be computed
+     * @param cursor current cursor position in the given code
+     * @return the known qualified names
+     */
+    public abstract QualifiedNames listQualifiedNames(String code, int cursor);
+
+    /**
      * Internal only constructor
      */
     SourceCodeAnalysis() {}
@@ -80,7 +102,7 @@
      */
     public static class CompletionInfo {
 
-        public CompletionInfo(Completeness completeness, int unitEndPos, String source, String remaining) {
+        CompletionInfo(Completeness completeness, int unitEndPos, String source, String remaining) {
             this.completeness = completeness;
             this.unitEndPos = unitEndPos;
             this.source = source;
@@ -198,4 +220,65 @@
          */
         public final boolean isSmart;
     }
+
+    /**
+     * List of possible qualified names.
+     */
+    public static final class QualifiedNames {
+
+        private final List<String> names;
+        private final int simpleNameLength;
+        private final boolean upToDate;
+        private final boolean resolvable;
+
+        QualifiedNames(List<String> names, int simpleNameLength, boolean upToDate, boolean resolvable) {
+            this.names = names;
+            this.simpleNameLength = simpleNameLength;
+            this.upToDate = upToDate;
+            this.resolvable = resolvable;
+        }
+
+        /**
+         * Known qualified names for the given simple name in the original code.
+         *
+         * @return known qualified names
+         */
+        public List<String> getNames() {
+            return names;
+        }
+
+        /**
+         * The length of the simple name in the original code for which the
+         * qualified names where gathered.
+         *
+         * @return the length of the simple name; -1 if there is no name immediately left to the cursor for
+         *         which the candidates could be computed
+         */
+        public int getSimpleNameLength() {
+            return simpleNameLength;
+        }
+
+        /**
+         * Whether the result is based on up to date data. The
+         * {@link SourceCodeAnalysis#listQualifiedNames(java.lang.String, int) listQualifiedNames}
+         * method may return before the classpath is fully inspected, in which case this method will
+         * return {@code false}. If the result is based on a fully inspected classpath, this method
+         * will return {@code true}.
+         *
+         * @return true iff the results is based on up-to-date data
+         */
+        public boolean isUpToDate() {
+            return upToDate;
+        }
+
+        /**
+         * Whether the given simple name in the original code refers to a resolvable element.
+         *
+         * @return true iff the given simple name in the original code refers to a resolvable element
+         */
+        public boolean isResolvable() {
+            return resolvable;
+        }
+
+    }
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Wed Jul 05 21:24:14 2017 +0200
@@ -79,13 +79,23 @@
 import java.nio.file.DirectoryStream;
 import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -99,6 +109,7 @@
 import java.util.stream.StreamSupport;
 
 import javax.lang.model.SourceVersion;
+
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.QualifiedNameable;
@@ -118,12 +129,30 @@
  * @author Robert Field
  */
 class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
+
+    private static final Map<Path, ClassIndex> PATH_TO_INDEX = new HashMap<>();
+    private static final ExecutorService INDEXER = Executors.newFixedThreadPool(1, r -> {
+        Thread t = new Thread(r);
+        t.setDaemon(true);
+        t.setUncaughtExceptionHandler((thread, ex) -> ex.printStackTrace());
+        return t;
+    });
+
     private final JShell proc;
     private final CompletenessAnalyzer ca;
+    private final Map<Path, ClassIndex> currentIndexes = new HashMap<>();
+    private int indexVersion;
+    private int classpathVersion;
+    private final Object suspendLock = new Object();
+    private int suspend;
 
     SourceCodeAnalysisImpl(JShell proc) {
         this.proc = proc;
         this.ca = new CompletenessAnalyzer(proc);
+
+        int cpVersion = classpathVersion = 1;
+
+        INDEXER.submit(() -> refreshIndexes(cpVersion));
     }
 
     @Override
@@ -203,6 +232,15 @@
 
     @Override
     public List<Suggestion> completionSuggestions(String code, int cursor, int[] anchor) {
+        suspendIndexing();
+        try {
+            return completionSuggestionsImpl(code, cursor, anchor);
+        } finally {
+            resumeIndexing();
+        }
+    }
+
+    private List<Suggestion> completionSuggestionsImpl(String code, int cursor, int[] anchor) {
         code = code.substring(0, cursor);
         Matcher m = JAVA_IDENTIFIER.matcher(code);
         String identifier = "";
@@ -390,8 +428,11 @@
 
                 long start = sp.getStartPosition(topLevel, tree);
                 long end = sp.getEndPosition(topLevel, tree);
+                long prevEnd = deepest[0] != null ? sp.getEndPosition(topLevel, deepest[0].getLeaf()) : -1;
 
-                if (start <= pos && pos <= end) {
+                if (start <= pos && pos <= end &&
+                    (start != end || prevEnd != end || deepest[0] == null ||
+                     deepest[0].getParentPath().getLeaf() != getCurrentPath().getLeaf())) {
                     deepest[0] = new TreePath(getCurrentPath(), tree);
                     return super.scan(tree, p);
                 }
@@ -589,32 +630,28 @@
                 .collect(toList());
     }
 
-    private Set<String> emptyContextPackages = null;
+    void classpathChanged() {
+        synchronized (currentIndexes) {
+            int cpVersion = ++classpathVersion;
 
-    void classpathChanged() {
-        emptyContextPackages = null;
+            INDEXER.submit(() -> refreshIndexes(cpVersion));
+        }
     }
 
     private Set<PackageElement> listPackages(AnalyzeTask at, String enclosingPackage) {
-        Set<String> packs;
-
-        if (enclosingPackage.isEmpty() && emptyContextPackages != null) {
-            packs = emptyContextPackages;
-        } else {
-            packs = new HashSet<>();
-
-            listPackages(StandardLocation.PLATFORM_CLASS_PATH, enclosingPackage, packs);
-            listPackages(StandardLocation.CLASS_PATH, enclosingPackage, packs);
-            listPackages(StandardLocation.SOURCE_PATH, enclosingPackage, packs);
-
-            if (enclosingPackage.isEmpty()) {
-                emptyContextPackages = packs;
-            }
+        synchronized (currentIndexes) {
+            return currentIndexes.values()
+                                 .stream()
+                                 .flatMap(idx -> idx.packages.stream())
+                                 .filter(p -> enclosingPackage.isEmpty() || p.startsWith(enclosingPackage + "."))
+                                 .map(p -> {
+                                     int dot = p.indexOf('.', enclosingPackage.length() + 1);
+                                     return dot == (-1) ? p : p.substring(0, dot);
+                                 })
+                                 .distinct()
+                                 .map(p -> createPackageElement(at, p))
+                                 .collect(Collectors.toSet());
         }
-
-        return packs.stream()
-                    .map(pkg -> createPackageElement(at, pkg))
-                    .collect(Collectors.toSet());
     }
 
     private PackageElement createPackageElement(AnalyzeTask at, String packageName) {
@@ -625,79 +662,6 @@
         return existing;
     }
 
-    private void listPackages(Location loc, String enclosing, Set<String> packs) {
-        Iterable<? extends Path> paths = proc.taskFactory.fileManager().getLocationAsPaths(loc);
-
-        if (paths == null)
-            return ;
-
-        for (Path p : paths) {
-            listPackages(p, enclosing, packs);
-        }
-    }
-
-    private void listPackages(Path path, String enclosing, Set<String> packages) {
-        try {
-            if (path.equals(Paths.get("JRT_MARKER_FILE"))) {
-                FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
-                Path modules = jrtfs.getPath("modules");
-                try (DirectoryStream<Path> stream = Files.newDirectoryStream(modules)) {
-                    for (Path c : stream) {
-                        listDirectory(c, enclosing, packages);
-                    }
-                }
-            } else if (!Files.isDirectory(path)) {
-                if (Files.exists(path)) {
-                    ClassLoader cl = SourceCodeAnalysisImpl.class.getClassLoader();
-
-                    try (FileSystem zip = FileSystems.newFileSystem(path, cl)) {
-                        listDirectory(zip.getRootDirectories().iterator().next(), enclosing, packages);
-                    }
-                }
-            } else {
-                listDirectory(path, enclosing, packages);
-            }
-        } catch (IOException ex) {
-            proc.debug(ex, "SourceCodeAnalysisImpl.listPackages(" + path.toString() + ", " + enclosing + ", " + packages + ")");
-        }
-    }
-
-    private void listDirectory(Path path, String enclosing, Set<String> packages) throws IOException {
-        String separator = path.getFileSystem().getSeparator();
-        Path resolved = path.resolve(enclosing.replace(".", separator));
-
-        if (Files.isDirectory(resolved)) {
-            try (DirectoryStream<Path> ds = Files.newDirectoryStream(resolved)) {
-                for (Path entry : ds) {
-                    String name = pathName(entry);
-
-                    if (SourceVersion.isIdentifier(name) &&
-                        Files.isDirectory(entry) &&
-                        validPackageCandidate(entry)) {
-                        packages.add(enclosing + (enclosing.isEmpty() ? "" : ".") + name);
-                    }
-                }
-            }
-        }
-    }
-
-    private boolean validPackageCandidate(Path p) throws IOException {
-        try (Stream<Path> dir = Files.list(p)) {
-            return dir.anyMatch(e -> Files.isDirectory(e) && SourceVersion.isIdentifier(pathName(e)) ||
-                                e.getFileName().toString().endsWith(".class"));
-        }
-    }
-
-    private String pathName(Path p) {
-        String separator = p.getFileSystem().getSeparator();
-        String name = p.getFileName().toString();
-
-        if (name.endsWith(separator)) //jars have '/' appended
-            name = name.substring(0, name.length() - separator.length());
-
-        return name;
-    }
-
     private Element createArrayLengthSymbol(AnalyzeTask at, TypeMirror site) {
         Name length = Names.instance(at.getContext()).length;
         Type intType = Symtab.instance(at.getContext()).intType;
@@ -965,6 +929,15 @@
 
     @Override
     public String documentation(String code, int cursor) {
+        suspendIndexing();
+        try {
+            return documentationImpl(code, cursor);
+        } finally {
+            resumeIndexing();
+        }
+    }
+
+    private String documentationImpl(String code, int cursor) {
         code = code.substring(0, cursor);
         if (code.trim().isEmpty()) { //TODO: comment handling
             code += ";";
@@ -1074,4 +1047,347 @@
         }
         return arrayType;
     }
+
+    @Override
+    public String analyzeType(String code, int cursor) {
+        code = code.substring(0, cursor);
+        CompletionInfo completionInfo = analyzeCompletion(code);
+        if (!completionInfo.completeness.isComplete)
+            return null;
+        if (completionInfo.completeness == Completeness.COMPLETE_WITH_SEMI) {
+            code += ";";
+        }
+
+        OuterWrap codeWrap;
+        switch (guessKind(code)) {
+            case IMPORT: case METHOD: case CLASS: case ENUM:
+            case INTERFACE: case ANNOTATION_TYPE: case VARIABLE:
+                return null;
+            default:
+                codeWrap = wrapInClass(Wrap.methodWrap(code));
+                break;
+        }
+        AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap);
+        SourcePositions sp = at.trees().getSourcePositions();
+        CompilationUnitTree topLevel = at.firstCuTree();
+        int pos = codeWrap.snippetIndexToWrapIndex(code.length());
+        TreePath tp = pathFor(topLevel, sp, pos);
+        while (ExpressionTree.class.isAssignableFrom(tp.getParentPath().getLeaf().getKind().asInterface()) &&
+               tp.getParentPath().getLeaf().getKind() != Kind.ERRONEOUS &&
+               tp.getParentPath().getParentPath() != null)
+            tp = tp.getParentPath();
+        TypeMirror type = at.trees().getTypeMirror(tp);
+
+        if (type == null)
+            return null;
+
+        switch (type.getKind()) {
+            case ERROR: case NONE: case OTHER:
+            case PACKAGE: case VOID:
+                return null; //not usable
+            case NULL:
+                type = at.getElements().getTypeElement("java.lang.Object").asType();
+                break;
+        }
+
+        return TreeDissector.printType(at, proc, type);
+    }
+
+    @Override
+    public QualifiedNames listQualifiedNames(String code, int cursor) {
+        code = code.substring(0, cursor);
+        if (code.trim().isEmpty()) {
+            return new QualifiedNames(Collections.emptyList(), -1, true, false);
+        }
+        OuterWrap codeWrap;
+        switch (guessKind(code)) {
+            case IMPORT:
+                return new QualifiedNames(Collections.emptyList(), -1, true, false);
+            case METHOD:
+                codeWrap = wrapInClass(Wrap.classMemberWrap(code));
+                break;
+            default:
+                codeWrap = wrapInClass(Wrap.methodWrap(code));
+                break;
+        }
+        AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap);
+        SourcePositions sp = at.trees().getSourcePositions();
+        CompilationUnitTree topLevel = at.firstCuTree();
+        TreePath tp = pathFor(topLevel, sp, codeWrap.snippetIndexToWrapIndex(code.length()));
+        if (tp.getLeaf().getKind() != Kind.IDENTIFIER) {
+            return new QualifiedNames(Collections.emptyList(), -1, true, false);
+        }
+        Scope scope = at.trees().getScope(tp);
+        TypeMirror type = at.trees().getTypeMirror(tp);
+        Element el = at.trees().getElement(tp);
+
+        boolean erroneous = (type.getKind() == TypeKind.ERROR && el.getKind() == ElementKind.CLASS) ||
+                            (el.getKind() == ElementKind.PACKAGE && el.getEnclosedElements().isEmpty());
+        String simpleName = ((IdentifierTree) tp.getLeaf()).getName().toString();
+        boolean upToDate;
+        List<String> result;
+
+        synchronized (currentIndexes) {
+            upToDate = classpathVersion == indexVersion;
+            result = currentIndexes.values()
+                                   .stream()
+                                   .flatMap(idx -> idx.classSimpleName2FQN.getOrDefault(simpleName,
+                                                                                        Collections.emptyList()).stream())
+                                   .distinct()
+                                   .filter(fqn -> isAccessible(at, scope, fqn))
+                                   .sorted()
+                                   .collect(Collectors.toList());
+        }
+
+        return new QualifiedNames(result, simpleName.length(), upToDate, !erroneous);
+    }
+
+    private boolean isAccessible(AnalyzeTask at, Scope scope, String fqn) {
+        TypeElement type = at.getElements().getTypeElement(fqn);
+        if (type == null)
+            return false;
+        return at.trees().isAccessible(scope, type);
+    }
+
+    //--------------------
+    // classpath indexing:
+    //--------------------
+
+    //the indexing can be suspended when a more important task is running:
+    private void waitIndexingNotSuspended() {
+        boolean suspendedNotified = false;
+        synchronized (suspendLock) {
+            while (suspend > 0) {
+                if (!suspendedNotified) {
+                    suspendedNotified = true;
+                }
+                try {
+                    suspendLock.wait();
+                } catch (InterruptedException ex) {
+                }
+            }
+        }
+    }
+
+    public void suspendIndexing() {
+        synchronized (suspendLock) {
+            suspend++;
+        }
+    }
+
+    public void resumeIndexing() {
+        synchronized (suspendLock) {
+            if (--suspend == 0) {
+                suspendLock.notifyAll();
+            }
+        }
+    }
+
+    //update indexes, either initially or after a classpath change:
+    private void refreshIndexes(int version) {
+        try {
+            Collection<Path> paths = new ArrayList<>();
+            MemoryFileManager fm = proc.taskFactory.fileManager();
+
+            appendPaths(fm, StandardLocation.PLATFORM_CLASS_PATH, paths);
+            appendPaths(fm, StandardLocation.CLASS_PATH, paths);
+            appendPaths(fm, StandardLocation.SOURCE_PATH, paths);
+
+            Map<Path, ClassIndex> newIndexes = new HashMap<>();
+
+            //setup existing/last known data:
+            for (Path p : paths) {
+                ClassIndex index = PATH_TO_INDEX.get(p);
+                if (index != null) {
+                    newIndexes.put(p, index);
+                }
+            }
+
+            synchronized (currentIndexes) {
+                //temporary setting old data:
+                currentIndexes.clear();
+                currentIndexes.putAll(newIndexes);
+            }
+
+            //update/compute the indexes if needed:
+            for (Path p : paths) {
+                waitIndexingNotSuspended();
+
+                ClassIndex index = indexForPath(p);
+                newIndexes.put(p, index);
+            }
+
+            synchronized (currentIndexes) {
+                currentIndexes.clear();
+                currentIndexes.putAll(newIndexes);
+            }
+        } catch (Exception ex) {
+            proc.debug(ex, "SourceCodeAnalysisImpl.refreshIndexes(" + version + ")");
+        } finally {
+            synchronized (currentIndexes) {
+                indexVersion = version;
+            }
+        }
+    }
+
+    private void appendPaths(MemoryFileManager fm, Location loc, Collection<Path> paths) {
+        Iterable<? extends Path> locationPaths = fm.getLocationAsPaths(loc);
+        if (locationPaths == null)
+            return ;
+        for (Path path : locationPaths) {
+            if (".".equals(path.toString())) {
+                //skip CWD
+                continue;
+            }
+
+            paths.add(path);
+        }
+    }
+
+    //create/update index a given JavaFileManager entry (which may be a JDK installation, a jar/zip file or a directory):
+    //if an index exists for the given entry, the existing index is kept unless the timestamp is modified
+    private ClassIndex indexForPath(Path path) {
+        if (isJRTMarkerFile(path)) {
+            FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
+            Path modules = jrtfs.getPath("modules");
+            return PATH_TO_INDEX.compute(path, (p, index) -> {
+                try {
+                    long lastModified = Files.getLastModifiedTime(modules).toMillis();
+                    if (index == null || index.timestamp != lastModified) {
+                        try (DirectoryStream<Path> stream = Files.newDirectoryStream(modules)) {
+                            index = doIndex(lastModified, path, stream);
+                        }
+                    }
+                    return index;
+                } catch (IOException ex) {
+                    proc.debug(ex, "SourceCodeAnalysisImpl.indexesForPath(" + path.toString() + ")");
+                    return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap());
+                }
+            });
+        } else if (!Files.isDirectory(path)) {
+            if (Files.exists(path)) {
+                return PATH_TO_INDEX.compute(path, (p, index) -> {
+                    try {
+                        long lastModified = Files.getLastModifiedTime(p).toMillis();
+                        if (index == null || index.timestamp != lastModified) {
+                            ClassLoader cl = SourceCodeAnalysisImpl.class.getClassLoader();
+
+                            try (FileSystem zip = FileSystems.newFileSystem(path, cl)) {
+                                index = doIndex(lastModified, path, zip.getRootDirectories());
+                            }
+                        }
+                        return index;
+                    } catch (IOException ex) {
+                        proc.debug(ex, "SourceCodeAnalysisImpl.indexesForPath(" + path.toString() + ")");
+                        return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap());
+                    }
+                });
+            } else {
+                return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap());
+            }
+        } else {
+            return PATH_TO_INDEX.compute(path, (p, index) -> {
+                //no persistence for directories, as we cannot check timestamps:
+                if (index == null) {
+                    index = doIndex(-1, path, Arrays.asList(p));
+                }
+                return index;
+            });
+        }
+    }
+
+    static boolean isJRTMarkerFile(Path path) {
+        return path.equals(Paths.get("JRT_MARKER_FILE"));
+    }
+
+    //create an index based on the content of the given dirs; the original JavaFileManager entry is originalPath.
+    private ClassIndex doIndex(long timestamp, Path originalPath, Iterable<? extends Path> dirs) {
+        Set<String> packages = new HashSet<>();
+        Map<String, Collection<String>> classSimpleName2FQN = new HashMap<>();
+
+        for (Path d : dirs) {
+            try {
+                Files.walkFileTree(d, new FileVisitor<Path>() {
+                    int depth;
+                    @Override
+                    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+                        waitIndexingNotSuspended();
+                        if (depth++ == 0)
+                            return FileVisitResult.CONTINUE;
+                        String dirName = dir.getFileName().toString();
+                        String sep = dir.getFileSystem().getSeparator();
+                        dirName = dirName.endsWith(sep) ? dirName.substring(0, dirName.length() - sep.length())
+                                                        : dirName;
+                        if (SourceVersion.isIdentifier(dirName))
+                            return FileVisitResult.CONTINUE;
+                        return FileVisitResult.SKIP_SUBTREE;
+                    }
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                        waitIndexingNotSuspended();
+                        if (file.getFileName().toString().endsWith(".class")) {
+                            String relativePath = d.relativize(file).toString();
+                            String binaryName = relativePath.substring(0, relativePath.length() - 6).replace('/', '.');
+                            int packageDot = binaryName.lastIndexOf('.');
+                            if (packageDot > (-1)) {
+                                packages.add(binaryName.substring(0, packageDot));
+                            }
+                            String typeName = binaryName.replace('$', '.');
+                            addClassName2Map(classSimpleName2FQN, typeName);
+                        }
+                        return FileVisitResult.CONTINUE;
+                    }
+                    @Override
+                    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+                        return FileVisitResult.CONTINUE;
+                    }
+                    @Override
+                    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                        depth--;
+                        return FileVisitResult.CONTINUE;
+                    }
+                });
+            } catch (IOException ex) {
+                proc.debug(ex, "doIndex(" + d.toString() + ")");
+            }
+        }
+
+        return new ClassIndex(timestamp, originalPath, packages, classSimpleName2FQN);
+    }
+
+    private static void addClassName2Map(Map<String, Collection<String>> classSimpleName2FQN, String typeName) {
+        int simpleNameDot = typeName.lastIndexOf('.');
+        classSimpleName2FQN.computeIfAbsent(typeName.substring(simpleNameDot + 1), n -> new LinkedHashSet<>())
+                           .add(typeName);
+    }
+
+    //holder for indexed data about a given path
+    public static final class ClassIndex {
+        public final long timestamp;
+        public final Path forPath;
+        public final Set<String> packages;
+        public final Map<String, Collection<String>> classSimpleName2FQN;
+
+        public ClassIndex(long timestamp, Path forPath, Set<String> packages, Map<String, Collection<String>> classSimpleName2FQN) {
+            this.timestamp = timestamp;
+            this.forPath = forPath;
+            this.packages = packages;
+            this.classSimpleName2FQN = classSimpleName2FQN;
+        }
+
+    }
+
+    //for tests, to be able to wait until the indexing finishes:
+    public void waitBackgroundTaskFinished() throws Exception {
+        boolean upToDate;
+        synchronized (currentIndexes) {
+            upToDate = classpathVersion == indexVersion;
+        }
+        while (!upToDate) {
+            INDEXER.submit(() -> {}).get();
+            synchronized (currentIndexes) {
+                upToDate = classpathVersion == indexVersion;
+            }
+        }
+    }
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Wed Jul 05 21:24:14 2017 +0200
@@ -41,13 +41,14 @@
 import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.code.Types;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
-import com.sun.tools.javac.util.JavacMessages;
 import com.sun.tools.javac.util.Name;
 import static jdk.jshell.Util.isDoIt;
+import jdk.jshell.TaskFactory.AnalyzeTask;
 import jdk.jshell.Wrap.Range;
+
 import java.util.List;
 import java.util.Locale;
-import java.util.function.BinaryOperator;
+
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 import javax.lang.model.type.TypeMirror;
@@ -209,7 +210,7 @@
     }
 
 
-    ExpressionInfo typeOfReturnStatement(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
+    ExpressionInfo typeOfReturnStatement(AnalyzeTask at, JShell state) {
         ExpressionInfo ei = new ExpressionInfo();
         Tree unitTree = firstStatement();
         if (unitTree instanceof ReturnTree) {
@@ -219,9 +220,7 @@
                 if (viPath != null) {
                     TypeMirror tm = trees().getTypeMirror(viPath);
                     if (tm != null) {
-                        Type type = (Type)tm;
-                        TypePrinter tp = new TypePrinter(messages, fullClassNameAndPackageToClass, type);
-                        ei.typeName = tp.visit(type, Locale.getDefault());
+                        ei.typeName = printType(at, state, tm);
                         switch (tm.getKind()) {
                             case VOID:
                             case NONE:
@@ -263,6 +262,12 @@
         return sg.toString();
     }
 
+    public static String printType(AnalyzeTask at, JShell state, TypeMirror type) {
+        Type typeImpl = (Type) type;
+        TypePrinter tp = new TypePrinter(at.messages(), state.maps::fullClassNameAndPackageToClass, typeImpl);
+        return tp.visit(typeImpl, Locale.getDefault());
+    }
+
     /**
      * Signature Generation
      */
--- a/langtools/test/TEST.groups	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/TEST.groups	Wed Jul 05 21:24:14 2017 +0200
@@ -22,15 +22,17 @@
 
 # Tiered testing definitions
 
-# All langtools tests are tier 1.
+# (Nearly) all langtools tests are tier 1.
 tier1 = \
     com \
     jdk \
     lib \
-    tools
+    tools \
+    -jdk/jshell/ToolReloadTest.java
 
-# No langtools tests are tier 2.
-tier2 = 
+# (Almost) no langtools tests are tier 2.
+tier2 = \
+    jdk/jshell/ToolReloadTest.java
 
 # No langtools tests are tier 3 either.
 tier3 = 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/ComputeFQNsTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,119 @@
+/*
+ * 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 8131027
+ * @summary Test Get FQNs
+ * @library /tools/lib
+ * @build KullaTesting TestingInputStream ToolBox Compiler
+ * @run testng ComputeFQNsTest
+ */
+
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import jdk.jshell.SourceCodeAnalysis.QualifiedNames;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+@Test
+public class ComputeFQNsTest extends KullaTesting {
+
+    private final Compiler compiler = new Compiler();
+    private final Path outDir = Paths.get("ComputeFQNsTest");
+
+    public void testAddImport() throws Exception {
+        compiler.compile(outDir, "package test1; public class TestClass { }", "package test2; public class TestClass { }");
+        String jarName = "test.jar";
+        compiler.jar(outDir, jarName, "test1/TestClass.class", "test2/TestClass.class");
+        addToClasspath(compiler.getPath(outDir).resolve(jarName));
+
+        assertInferredFQNs("LinkedList", "java.util.LinkedList");
+        assertInferredFQNs("ArrayList", "java.util.ArrayList");
+        assertInferredFQNs("TestClass", "test1.TestClass", "test2.TestClass");
+        assertInferredFQNs("CharSequence", "CharSequence".length(), true, "java.lang.CharSequence");
+        assertInferredFQNs("unresolvable");
+        assertInferredFQNs("void test(ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("void test(ArrayList l) throws InvocationTargetException", "InvocationTargetException".length(), false, "java.lang.reflect.InvocationTargetException");
+        assertInferredFQNs("void test(ArrayList l) { ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("<T extends ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("Object l = Arrays", "Arrays".length(), false, "java.util.Arrays");
+        assertInferredFQNs("class X<T extends ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("class X extends ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("class X extends java.util.ArrayList<TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X extends java.util.ArrayList<TypeMirror, TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X implements TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X implements TypeMirror, TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X implements java.util.List<TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X implements java.util.List<TypeMirror, TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X { ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+    }
+
+    @Test(enabled = false) //JDK-8150860
+    public void testSuspendIndexing() throws Exception {
+        compiler.compile(outDir, "package test; public class FQNTest { }");
+        String jarName = "test.jar";
+        compiler.jar(outDir, jarName, "test/FQNTest.class");
+        Path continueMarkFile = outDir.resolve("continuemark").toAbsolutePath();
+        Files.createDirectories(continueMarkFile.getParent());
+        try (Writer w = Files.newBufferedWriter(continueMarkFile)) {}
+
+        Path runMarkFile = outDir.resolve("runmark").toAbsolutePath();
+        Files.deleteIfExists(runMarkFile);
+
+        getState().sourceCodeAnalysis();
+
+        new Thread() {
+            @Override public void run() {
+                assertEval("{new java.io.FileOutputStream(\"" + runMarkFile.toAbsolutePath().toString() + "\").close();" +
+                           " while (java.nio.file.Files.exists(java.nio.file.Paths.get(\"" + continueMarkFile.toString() + "\"))) Thread.sleep(100); }");
+            }
+        }.start();
+
+        while (!Files.exists(runMarkFile))
+            Thread.sleep(100);
+
+        addToClasspath(compiler.getPath(outDir).resolve(jarName));
+
+        String code = "FQNTest";
+
+        QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length());
+
+        assertEquals(candidates.getNames(), Arrays.asList(), "Input: " + code + ", candidates=" + candidates.getNames());
+        assertEquals(candidates.isUpToDate(), false, "Input: " + code + ", up-to-date=" + candidates.isUpToDate());
+
+        Files.delete(continueMarkFile);
+
+        waitIndexingFinished();
+
+        candidates = getAnalysis().listQualifiedNames(code, code.length());
+
+        assertEquals(candidates.getNames(), Arrays.asList("test.FQNTest"), "Input: " + code + ", candidates=" + candidates.getNames());
+        assertEquals(true, candidates.isUpToDate(), "Input: " + code + ", up-to-date=" + candidates.isUpToDate());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/InferTypeTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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 8131027
+ * @summary Test Type Inference
+ * @library /tools/lib
+ * @build KullaTesting TestingInputStream ToolBox Compiler
+ * @run testng InferTypeTest
+ */
+
+import org.testng.annotations.Test;
+
+@Test
+public class InferTypeTest extends KullaTesting {
+
+    public void testTypeInference() {
+        assertInferredType("1", "int");
+        assertEval("import java.util.*;");
+        assertInferredType("new ArrayList<String>()", "ArrayList<String>");
+        assertInferredType("null", "Object");
+        assertInferredType("1 + ", null); //incomplete
+        assertInferredType("undef", null);  //unresolvable
+        assertEval("List<String> l1;");
+        assertEval("List<? extends String> l2;");
+        assertEval("List<? super String> l3;");
+        assertInferredType("l1", "List<String>");
+        assertInferredType("l2", "List<? extends String>");
+        assertInferredType("l3", "List<? super String>");
+        assertInferredType("l1.get(0)", "String");
+        assertInferredType("l2.get(0)", "String");
+        assertInferredType("l3.get(0)", "Object");
+        assertInferredType("\"\" + 1", "String");
+        assertEval("int i = 0;");
+        assertInferredType("i++", "int");
+        assertInferredType("++i", "int");
+        assertInferredType("i == 0 ? l1.get(0) : l2.get(0)", "String");
+        assertInferredType("", null);
+        assertInferredType("void test() { }", null);
+        assertInferredType("class Test { }", null);
+        assertInferredType("enum Test { A; }", null);
+        assertInferredType("interface Test { }", null);
+        assertInferredType("@interface Test { }", null);
+        assertInferredType("Object o;", null);
+    }
+
+}
--- a/langtools/test/jdk/jshell/KullaTesting.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/jdk/jshell/KullaTesting.java	Wed Jul 05 21:24:14 2017 +0200
@@ -24,6 +24,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.io.StringWriter;
+import java.lang.reflect.Method;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -61,6 +62,7 @@
 import jdk.jshell.SourceCodeAnalysis;
 import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
 import jdk.jshell.SourceCodeAnalysis.Completeness;
+import jdk.jshell.SourceCodeAnalysis.QualifiedNames;
 import jdk.jshell.SourceCodeAnalysis.Suggestion;
 import jdk.jshell.UnresolvedReferenceException;
 import org.testng.annotations.AfterMethod;
@@ -862,6 +864,8 @@
     }
 
     private List<String> computeCompletions(String code, Boolean isSmart) {
+        waitIndexingFinished();
+
         int cursor =  code.indexOf('|');
         code = code.replace("|", "");
         assertTrue(cursor > -1, "'|' expected, but not found in: " + code);
@@ -874,6 +878,37 @@
                           .collect(Collectors.toList());
     }
 
+    public void assertInferredType(String code, String expectedType) {
+        String inferredType = getAnalysis().analyzeType(code, code.length());
+
+        assertEquals(inferredType, expectedType, "Input: " + code + ", " + inferredType);
+    }
+
+    public void assertInferredFQNs(String code, String... fqns) {
+        assertInferredFQNs(code, code.length(), false, fqns);
+    }
+
+    public void assertInferredFQNs(String code, int simpleNameLen, boolean resolvable, String... fqns) {
+        waitIndexingFinished();
+
+        QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length());
+
+        assertEquals(candidates.getNames(), Arrays.asList(fqns), "Input: " + code + ", candidates=" + candidates.getNames());
+        assertEquals(candidates.getSimpleNameLength(), simpleNameLen, "Input: " + code + ", simpleNameLen=" + candidates.getSimpleNameLength());
+        assertEquals(candidates.isResolvable(), resolvable, "Input: " + code + ", resolvable=" + candidates.isResolvable());
+    }
+
+    protected void waitIndexingFinished() {
+        try {
+            Method waitBackgroundTaskFinished = getAnalysis().getClass().getDeclaredMethod("waitBackgroundTaskFinished");
+
+            waitBackgroundTaskFinished.setAccessible(true);
+            waitBackgroundTaskFinished.invoke(getAnalysis());
+        } catch (Exception ex) {
+            throw new AssertionError("Cannot wait for indexing end.", ex);
+        }
+    }
+
     public void assertDocumentation(String code, String... expected) {
         int cursor =  code.indexOf('|');
         code = code.replace("|", "");
--- a/langtools/test/jdk/jshell/ToolReloadTest.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/jdk/jshell/ToolReloadTest.java	Wed Jul 05 21:24:14 2017 +0200
@@ -23,6 +23,7 @@
 
 /*
  * @test
+ * @key intermittent
  * @bug 8081845 8147898
  * @summary Tests for /reload in JShell tool
  * @modules jdk.compiler/com.sun.tools.javac.api
--- a/langtools/test/tools/javac/6257443/T6257443.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/tools/javac/6257443/T6257443.java	Wed Jul 05 21:24:14 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, 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
@@ -31,13 +31,7 @@
  *
  * @clean foo.package-info
  *
- * @compile -XD-printflat package-info.java
- * @run main/othervm T6257443 -no foo/package-info.class
- *
- * @compile -XD-stubs package-info.java
- * @run main/othervm T6257443 -no foo/package-info.class
- *
- * @compile -XD-printsource package-info.java
+ * @compile -printsource package-info.java
  * @run main/othervm T6257443 -no foo/package-info.class
  */
 
--- a/langtools/test/tools/javac/6521805/T6521805a.java	Wed Jul 05 21:22:48 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6521805
- * @summary Regression: JDK5/JDK6 javac allows write access to outer class reference
- * @author mcimadamore
- *
- * @compile/fail/ref=T6521805a_1.out T6521805a.java -XDrawDiagnostics
- * @compile/ref=T6521805a_2.out T6521805a.java -XDwarnOnSyntheticConflicts -XDrawDiagnostics
- */
-
-class T6521805a {
-
-    static class Outer {
-        T6521805a this$0 = null;
-    }
-
-    public class Inner extends Outer {
-        public void foo() {
-            this$0 = new T6521805a();
-        }
-    }
-}
--- a/langtools/test/tools/javac/6521805/T6521805a_1.out	Wed Jul 05 21:22:48 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-T6521805a.java:17:12: compiler.err.synthetic.name.conflict: this$0, T6521805a.Outer
-1 error
--- a/langtools/test/tools/javac/6521805/T6521805a_2.out	Wed Jul 05 21:22:48 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-T6521805a.java:17:12: compiler.warn.synthetic.name.conflict: this$0, T6521805a.Outer
-1 warning
--- a/langtools/test/tools/javac/api/taskListeners/EventsBalancedTest.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/tools/javac/api/taskListeners/EventsBalancedTest.java	Wed Jul 05 21:24:14 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
@@ -61,8 +61,6 @@
 
         test(null, Arrays.asList(a, b));
         test(null, Arrays.asList(b, a));
-        test(Arrays.asList("-XD-relax"), Arrays.asList(a, b));
-        test(Arrays.asList("-XD-relax"), Arrays.asList(b, a));
 
         for (CompileState stop : CompileState.values()) {
             test(Arrays.asList("-XDshouldStopPolicyIfNoError=" + stop,
--- a/langtools/test/tools/javac/diags/CheckResourceKeys.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/tools/javac/diags/CheckResourceKeys.java	Wed Jul 05 21:24:14 2017 +0200
@@ -231,22 +231,15 @@
         "compiler.err.type.var.more.than.once.in.result",   // UNUSED
         "compiler.misc.non.denotable.type",                 // UNUSED
         "compiler.misc.unnamed.package",                    // should be required, CR 6964147
-        "compiler.misc.verbose.retro",                      // UNUSED
-        "compiler.misc.verbose.retro.with",                 // UNUSED
-        "compiler.misc.verbose.retro.with.list",            // UNUSED
         "compiler.warn.proc.type.already.exists",           // TODO in JavacFiler
         "javac.err.invalid.arg",                            // UNUSED ??
         "javac.opt.arg.class",                              // UNUSED ??
         "javac.opt.arg.pathname",                           // UNUSED ??
         "javac.opt.moreinfo",                               // option commented out
         "javac.opt.nogj",                                   // UNUSED
-        "javac.opt.printflat",                              // option commented out
         "javac.opt.printsearch",                            // option commented out
         "javac.opt.prompt",                                 // option commented out
-        "javac.opt.retrofit",                               // UNUSED
-        "javac.opt.s",                                      // option commented out
-        "javac.opt.scramble",                               // option commented out
-        "javac.opt.scrambleall"                             // option commented out
+        "javac.opt.s"                                       // option commented out
         ));
 
     /**
--- a/langtools/test/tools/javac/diags/examples.not-yet.txt	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples.not-yet.txt	Wed Jul 05 21:24:14 2017 +0200
@@ -86,9 +86,6 @@
 compiler.misc.undecl.type.var                           # ClassReader
 compiler.misc.unicode.str.not.supported                 # ClassReader
 compiler.misc.malformed.vararg.method                   # ClassReader
-compiler.misc.verbose.retro                             # UNUSED
-compiler.misc.verbose.retro.with                        # UNUSED
-compiler.misc.verbose.retro.with.list                   # UNUSED
 compiler.misc.version.not.available                     # JavaCompiler; implies build error
 compiler.misc.where.description.captured
 compiler.misc.where.typevar.1
--- a/langtools/test/tools/javac/diags/examples/WarnSyntheticNameConflict.java	Wed Jul 05 21:22:48 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2010, 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.
- */
-
-// key: compiler.warn.synthetic.name.conflict
-// options: -XDwarnOnSyntheticConflicts
-
-class WarnSyntheticNameConflict {
-
-    static class Outer {
-        WarnSyntheticNameConflict this$0 = null;
-    }
-
-    public class Inner extends Outer { }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/file/T8150475.java	Wed Jul 05 21:24:14 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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
+ * @compile -sourcepath / T8150475.java
+ */
+
+class T8150475 { }
+
--- a/langtools/test/tools/sjavac/IdleShutdown.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/tools/sjavac/IdleShutdown.java	Wed Jul 05 21:24:14 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
@@ -65,11 +65,11 @@
         // Use Sjavac object and wait less than TIMEOUT_MS in between calls
         Thread.sleep(TIMEOUT_MS - 1000);
         log("Compiling");
-        service.compile(new String[0], null, null);
+        service.compile(new String[0]);
 
         Thread.sleep(TIMEOUT_MS - 1000);
         log("Compiling");
-        service.compile(new String[0], null, null);
+        service.compile(new String[0]);
 
         if (timeoutTimestamp.get() != -1)
             throw new AssertionError("Premature timeout detected.");
@@ -103,7 +103,7 @@
         public void shutdown() {
         }
         @Override
-        public int compile(String[] args, Writer out, Writer err) {
+        public int compile(String[] args) {
             // Attempt to trigger idle timeout during a call by sleeping
             try {
                 Thread.sleep(TIMEOUT_MS + 1000);
--- a/langtools/test/tools/sjavac/PooledExecution.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/langtools/test/tools/sjavac/PooledExecution.java	Wed Jul 05 21:24:14 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,10 +30,12 @@
  * @build Wrapper
  * @run main Wrapper PooledExecution
  */
+import java.io.PrintWriter;
 import java.io.Writer;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import com.sun.tools.sjavac.Log;
 import com.sun.tools.sjavac.comp.PooledSjavac;
 import com.sun.tools.sjavac.server.Sjavac;
 
@@ -67,7 +69,7 @@
             for (int i = 0; i < NUM_REQUESTS; i++) {
                 tasks[i] = new Thread() {
                     public void run() {
-                        service.compile(new String[0], null, null);
+                        service.compile(new String[0]);
                         tasksFinished.incrementAndGet();
                     }
                 };
@@ -109,7 +111,7 @@
             AtomicInteger activeRequests = new AtomicInteger(0);
 
             @Override
-            public int compile(String[] args, Writer out, Writer err) {
+            public int compile(String[] args) {
                 leftToStart.countDown();
                 int numActiveRequests = activeRequests.incrementAndGet();
                 System.out.printf("Left to start: %2d / Currently active: %2d%n",
--- a/make/Init.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/make/Init.gmk	Wed Jul 05 21:24:14 2017 +0200
@@ -154,6 +154,9 @@
           # Do nothing
         endif
 
+    # Do not let make delete spec files even if aborted while doing a reconfigure
+    .PRECIOUS: $(SPECS)
+
     # Unless reconfigure is explicitely called, let all main targets depend on
     # the spec files to be up to date.
     ifeq ($(findstring reconfigure, $(INIT_TARGETS)), )
--- a/make/common/CORE_PKGS.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/make/common/CORE_PKGS.gmk	Wed Jul 05 21:24:14 2017 +0200
@@ -103,6 +103,7 @@
     java.lang.reflect \
     java.math \
     java.net \
+    java.net.http \
     java.net.spi \
     java.nio \
     java.nio.channels \
--- a/make/common/NativeCompilation.gmk	Wed Jul 05 21:22:48 2017 +0200
+++ b/make/common/NativeCompilation.gmk	Wed Jul 05 21:24:14 2017 +0200
@@ -651,12 +651,15 @@
 
       $$($1_RES): $$($1_VERSIONINFO_RESOURCE) $$($1_RES_VARDEPS_FILE)
 		$$(call LogInfo, Compiling resource $$(notdir $$($1_VERSIONINFO_RESOURCE)) (for $$(notdir $$($1_TARGET))))
+		$$(call MakeDir, $$(@D) $$($1_OBJECT_DIR))
 		$$(call ExecuteWithLog, $$@, \
 		    $$($1_RC) $$($1_RC_FLAGS) $$($1_SYSROOT_CFLAGS) $(CC_OUT_OPTION)$$@ \
 		    $$($1_VERSIONINFO_RESOURCE))
                 # Windows RC compiler does not support -showIncludes, so we mis-use CL for this.
-		$$($1_CC) $$($1_RC_FLAGS) $$($1_SYSROOT_CFLAGS) -showIncludes -nologo -TC \
-		    $(CC_OUT_OPTION)$$($1_RES_DEP).obj $$($1_VERSIONINFO_RESOURCE) > $$($1_RES_DEP).raw 2>&1 || true ; \
+		$$(call ExecuteWithLog, $$($1_RES_DEP).obj, \
+		    $$($1_CC) $$($1_RC_FLAGS) $$($1_SYSROOT_CFLAGS) -showIncludes -nologo -TC \
+		    $(CC_OUT_OPTION)$$($1_RES_DEP).obj -P -Fi$$($1_RES_DEP).pp \
+		    $$($1_VERSIONINFO_RESOURCE)) > $$($1_RES_DEP).raw 2>&1 || true ; \
 		$(ECHO) $$($1_RES): \\ > $$($1_RES_DEP) ; \
 		$(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_RES_DEP).raw >> $$($1_RES_DEP) ; \
 		$(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_RES_DEP) > $$($1_RES_DEP_TARGETS)
@@ -670,7 +673,7 @@
         $1_REAL_MAPFILE := $$($1_OBJECT_DIR)/mapfile
 
         $$($1_REAL_MAPFILE) : $$($1_MAPFILE) $$($1_REORDER)
-		$$(MKDIR) -p $$(@D)
+		$$(call MakeDir, $$(@D))
 		$$(CP) $$($1_MAPFILE) $$@.tmp
 		$$(SED) -e 's=OUTPUTDIR=$$($1_OBJECT_DIR)=' $$($1_REORDER) >> $$@.tmp
 		$$(MV) $$@.tmp $$@
@@ -768,7 +771,10 @@
       $1_EXTRA_LDFLAGS += "-implib:$$($1_OBJECT_DIR)/$$($1_LIBRARY).lib"
     endif
 
-    $1_EXTRA_LIBS += $(GLOBAL_LIBS)
+    # Create loadmap on AIX. Helps in diagnosing some problems.
+    ifneq ($(COMPILER_BINDCMD_FILE_FLAG),)
+      $1_EXTRA_LDFLAGS += $(COMPILER_BINDCMD_FILE_FLAG)$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).loadmap
+    endif
 
     $1_VARDEPS := $$($1_LD) $$($1_SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
         $$($1_LIBS) $$($1_EXTRA_LIBS) $$($1_CREATE_DEBUGINFO_CMDS) \
@@ -846,8 +852,6 @@
 
   ifneq (,$$($1_PROGRAM))
     # A executable binary has been specified, setup the target for it.
-    $1_EXTRA_LIBS += $(GLOBAL_LIBS)
-
     $1_VARDEPS := $$($1_LD) $$($1_SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
         $$($1_LIBS) $$($1_EXTRA_LIBS) $$($1_MT) \
         $$($1_CODESIGN) $$($1_CREATE_DEBUGINFO_CMDS) $$($1_MANIFEST_VERSION) \
--- a/modules.xml	Wed Jul 05 21:22:48 2017 +0200
+++ b/modules.xml	Wed Jul 05 21:24:14 2017 +0200
@@ -316,6 +316,10 @@
       <to>java.instrument</to>
     </export>
     <export>
+      <name>sun.net</name>
+      <to>java.httpclient</to>
+    </export>
+    <export>
       <name>sun.net.dns</name>
       <to>java.security.jgss</to>
       <to>jdk.naming.dns</to>
@@ -496,6 +500,7 @@
       <to>java.logging</to>
       <to>java.management</to>
       <to>java.prefs</to>
+      <to>java.httpclient</to>
     </export>
     <export>
       <name>sun.util.resources</name>
@@ -520,6 +525,7 @@
     <depend re-exports="true">java.compact2</depend>
     <depend re-exports="true">java.compiler</depend>
     <depend re-exports="true">java.instrument</depend>
+    <depend re-exports="true">java.httpclient</depend>
     <depend re-exports="true">java.management</depend>
     <depend re-exports="true">java.naming</depend>
     <depend re-exports="true">java.prefs</depend>
@@ -838,6 +844,13 @@
     </export>
   </module>
   <module>
+    <name>java.httpclient</name>
+    <depend>java.base</depend>
+    <export>
+      <name>java.net.http</name>
+    </export>
+  </module>
+  <module>
     <name>java.instrument</name>
     <depend>java.base</depend>
     <export>
--- a/nashorn/.hgtags	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/.hgtags	Wed Jul 05 21:24:14 2017 +0200
@@ -340,3 +340,4 @@
 a618d3e89fdea5361895ef142a59074fe7ae3d98 jdk-9+104
 4e9749cc32f15251d9b2d0eab4373529952902a3 jdk-9+105
 cfb3167456932b14c16a6d4cffd5fe295fbe01ff jdk-9+106
+8042e81b530e480dfdad41fd53a7a26f69ebba26 jdk-9+107
--- a/nashorn/make/build.xml	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/make/build.xml	Wed Jul 05 21:24:14 2017 +0200
@@ -242,6 +242,7 @@
     <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${nashorn.module.src.dir}/overview.html"
         extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
         additionalparam="-quiet" failonerror="true" useexternalfile="true">
+      <arg value="${javadoc.option}"/>
       <classpath>
         <pathelement location="${build.classes.dir}"/>
       </classpath>
@@ -261,6 +262,7 @@
     <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${nashorn.module.src.dir}/overview.html"
         extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
         additionalparam="-quiet" failonerror="true" useexternalfile="true">
+      <arg value="${javadoc.option}"/>
       <classpath>
         <pathelement location="${build.classes.dir}"/>
       </classpath>
@@ -276,6 +278,7 @@
     <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${nashorn.module.src.dir}/overview.html"
         extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
         additionalparam="-quiet" failonerror="true" useexternalfile="true">
+      <arg value="${javadoc.option}"/>
       <classpath>
         <pathelement location="${build.classes.dir}"/>
       </classpath>
@@ -289,6 +292,7 @@
     <javadoc destdir="${dist.javadoc.dir}" use="yes"
         windowtitle="Dynalink"
         additionalparam="-quiet" failonerror="true" useexternalfile="true">
+      <arg value="${javadoc.option}"/>
       <classpath>
         <pathelement location="${build.classes.dir}"/>
       </classpath>
--- a/nashorn/make/project.properties	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/make/project.properties	Wed Jul 05 21:24:14 2017 +0200
@@ -34,6 +34,8 @@
 javac.source=1.8
 javac.target=1.8
 
+javadoc.option=-tag "implSpec:a:Implementation Requirements:"
+
 # nashorn version information
 nashorn.version=0.1
 nashorn.fullversion=0.1
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/AbstractJSObject.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/AbstractJSObject.java	Wed Jul 05 21:24:14 2017 +0200
@@ -27,6 +27,7 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -34,19 +35,19 @@
  *
  * This class can also be subclassed by an arbitrary Java class. Nashorn will
  * treat objects of such classes just like nashorn script objects. Usual nashorn
- * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued
+ * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be delegated
  * to appropriate method call of this class.
  *
  * @since 1.8u40
  */
 public abstract class AbstractJSObject implements JSObject {
     /**
-     * Call this object as a JavaScript function. This is equivalent to
-     * 'func.apply(thiz, args)' in JavaScript.
-     *
-     * @param thiz 'this' object to be passed to the function
-     * @param args arguments to method
-     * @return result of call
+     * The default constructor.
+     */
+    public AbstractJSObject() {}
+
+    /**
+     * @implSpec This implementation always throws UnsupportedOperationException
      */
     @Override
     public Object call(final Object thiz, final Object... args) {
@@ -54,11 +55,7 @@
     }
 
     /**
-     * Call this 'constructor' JavaScript function to create a new object.
-     * This is equivalent to 'new func(arg1, arg2...)' in JavaScript.
-     *
-     * @param args arguments to method
-     * @return result of constructor call
+     * @implSpec This implementation always throws UnsupportedOperationException
      */
     @Override
     public Object newObject(final Object... args) {
@@ -66,10 +63,7 @@
     }
 
     /**
-     * Evaluate a JavaScript expression.
-     *
-     * @param s JavaScript expression to evaluate
-     * @return evaluation result
+     * @implSpec This imlementation always throws UnsupportedOperationException
      */
     @Override
     public Object eval(final String s) {
@@ -77,21 +71,16 @@
     }
 
     /**
-     * Retrieves a named member of this JavaScript object.
-     *
-     * @param name of member
-     * @return member
+     * @implSpec This implementation always returns null
      */
     @Override
     public Object getMember(final String name) {
+        Objects.requireNonNull(name);
         return null;
     }
 
     /**
-     * Retrieves an indexed member of this JavaScript object.
-     *
-     * @param index index slot to retrieve
-     * @return member
+     * @implSpec This implementation always returns null
      */
     @Override
     public Object getSlot(final int index) {
@@ -99,21 +88,16 @@
     }
 
     /**
-     * Does this object have a named member?
-     *
-     * @param name name of member
-     * @return true if this object has a member of the given name
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean hasMember(final String name) {
+        Objects.requireNonNull(name);
         return false;
     }
 
     /**
-     * Does this object have a indexed property?
-     *
-     * @param slot index to check
-     * @return true if this object has a slot
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean hasSlot(final int slot) {
@@ -121,31 +105,25 @@
     }
 
     /**
-     * Remove a named member from this JavaScript object
-     *
-     * @param name name of the member
+     * @implSpec This implementation is a no-op
      */
     @Override
     public void removeMember(final String name) {
+        Objects.requireNonNull(name);
         //empty
     }
 
     /**
-     * Set a named member in this JavaScript object
-     *
-     * @param name  name of the member
-     * @param value value of the member
+     * @implSpec This implementation is a no-op
      */
     @Override
     public void setMember(final String name, final Object value) {
+        Objects.requireNonNull(name);
         //empty
     }
 
     /**
-     * Set an indexed member in this JavaScript object
-     *
-     * @param index index of the member slot
-     * @param value value of the member
+     * @implSpec This implementation is a no-op
      */
     @Override
     public void setSlot(final int index, final Object value) {
@@ -155,9 +133,7 @@
     // property and value iteration
 
     /**
-     * Returns the set of all property names of this object.
-     *
-     * @return set of property names
+     * @implSpec This implementation returns empty set
      */
     @Override
     public Set<String> keySet() {
@@ -165,9 +141,7 @@
     }
 
     /**
-     * Returns the set of all property values of this object.
-     *
-     * @return set of property values.
+     * @implSpec This implementation returns empty set
      */
     @Override
     public Collection<Object> values() {
@@ -177,22 +151,13 @@
     // JavaScript instanceof check
 
     /**
-     * Checking whether the given object is an instance of 'this' object.
-     *
-     * @param instance instance to check
-     * @return true if the given 'instance' is an instance of this 'function' object
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean isInstance(final Object instance) {
         return false;
     }
 
-    /**
-     * Checking whether this object is an instance of the given 'clazz' object.
-     *
-     * @param clazz clazz to check
-     * @return true if this object is an instance of the given 'clazz'
-     */
     @Override
     public boolean isInstanceOf(final Object clazz) {
         if (clazz instanceof JSObject) {
@@ -202,20 +167,13 @@
         return false;
     }
 
-    /**
-     * ECMA [[Class]] property
-     *
-     * @return ECMA [[Class]] property value of this object
-     */
     @Override
     public String getClassName() {
         return getClass().getName();
     }
 
     /**
-     * Is this a function object?
-     *
-     * @return if this mirror wraps a ECMAScript function instance
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean isFunction() {
@@ -223,9 +181,7 @@
     }
 
     /**
-     * Is this a 'use strict' function object?
-     *
-     * @return true if this mirror represents a ECMAScript 'use strict' function
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean isStrictFunction() {
@@ -233,9 +189,7 @@
     }
 
     /**
-     * Is this an array object?
-     *
-     * @return if this mirror wraps a ECMAScript array object
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean isArray() {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/JSObject.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/JSObject.java	Wed Jul 05 21:24:14 2017 +0200
@@ -32,7 +32,7 @@
 /**
  * This interface can be implemented by an arbitrary Java class. Nashorn will
  * treat objects of such classes just like nashorn script objects. Usual nashorn
- * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued
+ * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be delegated
  * to appropriate method call of this interface.
  *
  * @since 1.8u40
@@ -42,7 +42,7 @@
      * Call this object as a JavaScript function. This is equivalent to
      * 'func.apply(thiz, args)' in JavaScript.
      *
-     * @param thiz 'this' object to be passed to the function
+     * @param thiz 'this' object to be passed to the function. This may be null.
      * @param args arguments to method
      * @return result of call
      */
@@ -70,6 +70,7 @@
      *
      * @param name of member
      * @return member
+     * @throws NullPointerException if name is null
      */
     public Object getMember(final String name);
 
@@ -101,6 +102,7 @@
      * Remove a named member from this JavaScript object
      *
      * @param name name of the member
+     * @throws NullPointerException if name is null
      */
     public void removeMember(final String name);
 
@@ -109,6 +111,7 @@
      *
      * @param name  name of the member
      * @param value value of the member
+     * @throws NullPointerException if name is null
      */
     public void setMember(final String name, final Object value);
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java	Wed Jul 05 21:24:14 2017 +0200
@@ -46,6 +46,8 @@
  */
 @SuppressWarnings("serial")
 public abstract class NashornException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
     // script file name
     private String fileName;
     // script line number
@@ -58,7 +60,7 @@
     private Object ecmaError;
 
     /**
-     * Constructor
+     * Constructor to initialize error message, file name, line and column numbers.
      *
      * @param msg       exception message
      * @param fileName  file name
@@ -70,7 +72,7 @@
     }
 
     /**
-     * Constructor
+     * Constructor to initialize error message, cause exception, file name, line and column numbers.
      *
      * @param msg       exception message
      * @param cause     exception cause
@@ -86,7 +88,7 @@
     }
 
     /**
-     * Constructor
+     * Constructor to initialize error message and cause exception.
      *
      * @param msg       exception message
      * @param cause     exception cause
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Wed Jul 05 21:24:14 2017 +0200
@@ -154,7 +154,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given class loader.
+     * Create a new Script engine initialized with the given class loader.
      *
      * @param appLoader class loader to be used as script "app" class loader.
      * @return newly created script engine.
@@ -167,7 +167,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given class filter.
+     * Create a new Script engine initialized with the given class filter.
      *
      * @param classFilter class filter to use.
      * @return newly created script engine.
@@ -181,7 +181,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given arguments.
+     * Create a new Script engine initialized with the given arguments.
      *
      * @param args arguments array passed to script engine.
      * @return newly created script engine.
@@ -195,7 +195,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given arguments.
+     * Create a new Script engine initialized with the given arguments and the given class loader.
      *
      * @param args arguments array passed to script engine.
      * @param appLoader class loader to be used as script "app" class loader.
@@ -210,7 +210,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given arguments.
+     * Create a new Script engine initialized with the given arguments, class loader and class filter.
      *
      * @param args arguments array passed to script engine.
      * @param appLoader class loader to be used as script "app" class loader.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Wed Jul 05 21:24:14 2017 +0200
@@ -287,22 +287,21 @@
         });
     }
 
-
     @Override
-    public boolean isInstance(final Object obj) {
-        if (! (obj instanceof ScriptObjectMirror)) {
+    public boolean isInstance(final Object instance) {
+        if (! (instance instanceof ScriptObjectMirror)) {
             return false;
         }
 
-        final ScriptObjectMirror instance = (ScriptObjectMirror)obj;
+        final ScriptObjectMirror mirror = (ScriptObjectMirror)instance;
         // if not belongs to my global scope, return false
-        if (global != instance.global) {
+        if (global != mirror.global) {
             return false;
         }
 
         return inGlobal(new Callable<Boolean>() {
             @Override public Boolean call() {
-                return sobj.isInstance(instance.sobj);
+                return sobj.isInstance(mirror.sobj);
             }
         });
     }
@@ -653,10 +652,10 @@
     }
 
     /**
-     * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
+     * Make a script object mirror on given object if needed.
      *
      * @param obj object to be wrapped/converted
-     * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+     * @param homeGlobal global to which this object belongs.
      * @return wrapped/converted object
      */
     public static Object wrap(final Object obj, final Object homeGlobal) {
@@ -664,13 +663,13 @@
     }
 
     /**
-     * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. The
-     * created wrapper will implement the Java {@code List} interface if {@code obj} is a JavaScript
-     * {@code Array} object; this is compatible with Java JSON libraries expectations. Arrays retrieved through its
+     * Make a script object mirror on given object if needed. The created wrapper will implement
+     * the Java {@code List} interface if {@code obj} is a JavaScript {@code Array} object;
+     * this is compatible with Java JSON libraries expectations. Arrays retrieved through its
      * properties (transitively) will also implement the list interface.
      *
      * @param obj object to be wrapped/converted
-     * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+     * @param homeGlobal global to which this object belongs.
      * @return wrapped/converted object
      */
     public static Object wrapAsJSONCompatible(final Object obj, final Object homeGlobal) {
@@ -678,10 +677,10 @@
     }
 
     /**
-     * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
+     * Make a script object mirror on given object if needed.
      *
      * @param obj object to be wrapped/converted
-     * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+     * @param homeGlobal global to which this object belongs.
      * @param jsonCompatible if true, the created wrapper will implement the Java {@code List} interface if
      * {@code obj} is a JavaScript {@code Array} object. Arrays retrieved through its properties (transitively)
      * will also implement the list interface.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java	Wed Jul 05 21:24:14 2017 +0200
@@ -74,9 +74,15 @@
      * @param func the function to wrap
      * @param sync the object to synchronize on
      * @return a synchronizing wrapper function
+     * @throws IllegalArgumentException if func does not represent a script function
      */
-    public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
-        return func.createSynchronized(unwrap(sync));
+    public static Object makeSynchronizedFunction(final Object func, final Object sync) {
+        final Object unwrapped = unwrap(func);
+        if (unwrapped instanceof ScriptFunction) {
+            return ((ScriptFunction)unwrapped).createSynchronized(unwrap(sync));
+        }
+
+        throw new IllegalArgumentException();
     }
 
     /**
@@ -84,9 +90,19 @@
      *
      * @param obj object to be wrapped
      * @return wrapped object
+     * @throws IllegalArgumentException if obj cannot be wrapped
      */
-    public static ScriptObjectMirror wrap(final ScriptObject obj) {
-        return (ScriptObjectMirror) ScriptObjectMirror.wrap(obj, Context.getGlobal());
+    public static ScriptObjectMirror wrap(final Object obj) {
+        if (obj instanceof ScriptObjectMirror) {
+            return (ScriptObjectMirror)obj;
+        }
+
+        if (obj instanceof ScriptObject) {
+            final ScriptObject sobj = (ScriptObject)obj;
+            return (ScriptObjectMirror) ScriptObjectMirror.wrap(sobj, Context.getGlobal());
+        }
+
+        throw new IllegalArgumentException();
     }
 
     /**
@@ -135,7 +151,8 @@
      * Convert the given object to the given type.
      *
      * @param obj object to be converted
-     * @param type destination type to convert to
+     * @param type destination type to convert to. type is either a Class
+     * or nashorn representation of a Java type returned by Java.type() call in script.
      * @return converted object
      */
     public static Object convert(final Object obj, final Object type) {
--- a/nashorn/test/script/basic/JDK-8026367.js	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/test/script/basic/JDK-8026367.js	Wed Jul 05 21:24:14 2017 +0200
@@ -37,10 +37,12 @@
     // Sync called with one argument will synchronize on this-object of invocation
     inc: sync(function(d) {
         this.count += d;
+        Assert.assertTrue(java.lang.Thread.holdsLock(this));
     }),
     // Pass explicit object to synchronize on as second argument
     dec: sync(function(d) {
         this.count -= d;
+        Assert.assertTrue(java.lang.Thread.holdsLock(obj));
     }, obj)
 };
 
--- a/nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8148140_Test.java	Wed Jul 05 21:22:48 2017 +0200
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8148140_Test.java	Wed Jul 05 21:24:14 2017 +0200
@@ -22,7 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package jdk.nashorn.internal.runtime.test;
+package jdk.nashorn.api.scripting.test;
 
 import java.util.Arrays;
 import javax.script.ScriptEngine;
@@ -70,4 +70,4 @@
         assertEquals(RESULT, engine.eval("Function.prototype.apply.call(f, null, [1,2,3])"));
     }
 
-}
\ No newline at end of file
+}